compiling error

K

Kapteyn's Star

Richard said:
Kapteyn's Star said:


No. Firstly, the word is "cast", not "typecast". :) Secondly, as I
explained earlier, no cast is required when converting between void *
and any other object pointer type, because an automatic conversion is
supplied.

So when I do:

int *i;
fread(&i, sizeof *i, n, file);

then the compiler automatically converts int* to void* before calling
fread()? but this is not okay with other types like int* -> float* and
others?

thanks for the rest of the details!
 
K

Kapteyn's Star

Keith said:
Richard Heathfield said:
Kapteyn's Star said:


No. Firstly, the word is "cast", not "typecast". :) Secondly, as I
explained earlier, no cast is required when converting between void *
and any other object pointer type, because an automatic conversion is
supplied.

And thirdly, fread() needn't be implemented in C.

It's likely that fread() is written in C in most implementations
(though not necessarily in portable C), and that it will implicitly
convert (not cast) the void* argument to unsigned char*.

[snip]

Like this?

unsigned char *p= buf; // buf is 1st arg to fread()

*p = next_char();
++p;

thanks.
 
B

Ben Bacarisse

Ben said:
Keith Thompson writes:
int array_2d[10][20] = { ... };
int elem = array_2d[5][6];

Figuring out how array_2d[5][6] resolves to an element of the 2d
array given the rules I've described is an interesting exercise.

I will try. Please correct me if im wrong. Here in the assignment
statement array_2d doesnt come under one of the 3 rules you gave so
it is converted to a pointer to its first element then the offset 5
is added to it and then the offset 6 is also added to derive the
value. Like:

int elem= *((array_2d + 5) + 6);

Not quite. You clearly get the that fact that:

array_2d[5][6] is (array_2d[5])[6]

i.e. array_2d first has [5] "applied" and then the result of that is
sub-scripted again (with 6). Applying the definition of [] in terms
if adding and de-referencing, we get:

array_2d[5] is *(array_2d + 5)
(array_2d[5])[6] is *(*(array_2d + 5) + 6)


So, what is array_2d converted to here? It is converted to pointer to
its first element. That is an array of 20 ints

Im sorry if i don't understand but do you mean 200 ints when you say 20
above?

No. In C, 2d arrays are arrays of 1d arrays. array_2d is a
five-element array. Each of these (including the first) is a
20-element int array.

Exactly. So a pointer to the first element must be to one of these
20-element arrays. Yes, it is followed by another 9 of them (in total
taking up space for 200 ints) but each element pointer points to just
one 20-element array.

When you write 'int stats[10]; stats;' the name of the array is
converted to a pointer to an int. A single int. You can use
arithmetic to get new pointers to the other ints in the array and
similarly, you can (and do) use arithmetic on array_2d's pointer value
to get at the other 9 elements of that array.
okay, so in declaration:

int a[2][3];

the elements are so formatted in memory in ascending address from left
to right in page??

+===================+===================+
|+-----+-----+-----+|+-----+-----+-----+|
|| 0,0 | 0,1 | 0,2 ||| 1,0 | 1,1 | 1,2 ||
|+-----+-----+-----+|+-----+-----+-----+|
+=======================================+

Perfect. Yes.
Writing this
type is messy in C and does not help with this exposition[1].

As per your note[1] then *(array_2d + 5) is of type int (*)[20]?

No, my note says that array_2d gets converted to a pointer of that
type. Adding 5 does not alter the type, but the * makes the
expression have type int [20].

This is the key step. Because this expression yields a value of array
type, it too gets converted -- to an int *. There is a problem here
that frustrates all people who teach C. You can't just write a bit of
C ask "what type is this"? You should really ask: "what type is the
object denoted by this?" or "what type does the result of this
expression have"? The two answers will be different if the "bit of C"
in question denotes an array.

*(array_2d + 5)

refers to an array -- the 6th sub-array inside array_2d. That "thing"
is of type int [20] but because this expression has an array type (and
there is no & or sizeof in sight) it is immediately converted to a
pointer to its first element -- an int. Thus the expression has a
value whose type is int *, but the expression also refers to an object
of type int [20].
Then what is type of array_2d + 5?

The same as per my note -- int (*)[20] -- and in this case there is no
ambiguity since the expression does not refer to or denote an object.

Adding a number to a pointer does not change the type. array_2d + i
for i = 0 to 10 are all valid and are all of type int (*)[20].

[Aside: you may be surprised by array_2d + 10, but C allows one to
construct a pointer to the element just past the end of an array. You
can't do much with it, but you can construct the pointer. C treats
single objects like arrays of length 1 for this purpose so given: 'int
i; int *ip = &i;' is it quite legal to calculate ip + 1.]
Now 5 gets added to that pointer. This arithmetic is done is units of
the size of the things being pointer to, in this case, 20-element int
arrays. Thus the result is a pointer that points at the 6th set of 20
ints.

[The standard does not describe it this way (in terms of sizes). It
simply says that adding /i/ to a pointer that points into an array
makes a pointer that points to the /i/th element. I described it my
way, because when that array is an array of arrays (as we have here)
the wording gets messy.]

This new pointer (array_2d + 5) has type "pointer to array of 20 int",
so applying the * to it results in a value whose type is "array of 20
int". Again, because this value is not used in one of the three
special situations, it is converted to a pointer to its first element:
in this case an int.

6 gets added to this int pointer, to give a pointer to the 7th
element in the 6th sub-array of array_2d. Applying the star, gives us
a modifiable lvalue that refers to this element (i.e. array_2d[5][6]
can be used like this: 'array_2d[5][6] = 42;' as well as like this:
'return array_2d[5][6] + 1;').

The tricky bit that array_2d[5] has array type. The value gets
converted to a pointer to array type and the arithmetic on the pointer
moves it about from one 20-element array to the next.

okay then what is the type of *(array_2d + 5) + 6? I think it is
int*?

Yes, it is of type int *. That is why the final * operation produces
an int -- the array element we wanted to get at.
Also what is type of just array_2d? is it int (*)[10][20]?

Not really. What you have written is the type a pointer to the whole
thing in other words that is the type of the expression &array_2d.
array_2d itself is an object of type int [10][20] -- it is not a
pointer at all but an array. Of course, my warning about writing a
bit of C and asking "what type is this" applies here. array_2d is the
name of an array. It is of type int [10][20], but the expression
array_2d, unadorned, has a value of type int (*)[20].

I say "unadorned" because the conversion only happen if the
array-valued expression is not the argument to & or sizeof[1]. That
is why &array_2d has type int (*)[10][20] and sizeof array_2d == 200 *
sizeof (int). In these contexts, array_2d remains unconverted and
refers to the whole array.

[Exactly the same happens with 1d arrays, of course. Given the
declaration 'int stats[20];' then stats is an object of type int [20]
and sizeof stats == 20 * sizeof (int). &stats is an expression whose
value is of type int (*)[20], but stats in other contexts gets
converted, so it is an expression whose value is of type int *.]
[1] It is 'int (*)[20]'.

Thank you very much Ben. Im not able to easily understand 2D arrays like
1D ones, but i'll keep reading your notes until i figure it.

[1] There is a third exception -- string literals used to initialise a
character array also don't get converted -- but that just muddies the
explanation because it is such a specific case.
 
B

Barry Schwarz

So when I do:

int *i;
fread(&i, sizeof *i, n, file);

then the compiler automatically converts int* to void* before calling
fread()? but this is not okay with other types like int* -> float* and
others?

It would have done this except that there is no int* in your call to
fread. By putting the & in front of the i, you have created an
expression of type int** and also rendered the code unusable. It
effectively says to read n items, each of which has size of int, into
a single variable which has size of int*. Even if n is one, it is
possible for sizeof(int) to be greater than sizeof(int*) and the code
would invoke undefined behavior. Chances are you really meant to say
read n items of size int into a series of objects of type int, the
first of which is pointed to by i. The code for this is
fread(i, sizeof *i, n file);
and of course i must be assigned a suitable value before the call.

If you want to fread into a declared object, use the &. If you want
to fread into whatever the object points to, don't.
thanks for the rest of the details!


Remove del for email
 
B

Barry Schwarz

Ben said:
Keith Thompson writes:
int array_2d[10][20] = { ... };
int elem = array_2d[5][6];

Figuring out how array_2d[5][6] resolves to an element of the 2d
array given the rules I've described is an interesting exercise.

I will try. Please correct me if im wrong. Here in the assignment
statement array_2d doesnt come under one of the 3 rules you gave so
it is converted to a pointer to its first element then the offset 5
is added to it and then the offset 6 is also added to derive the
value. Like:

int elem= *((array_2d + 5) + 6);

Not quite. You clearly get the that fact that:

array_2d[5][6] is (array_2d[5])[6]

i.e. array_2d first has [5] "applied" and then the result of that is
sub-scripted again (with 6). Applying the definition of [] in terms
if adding and de-referencing, we get:

array_2d[5] is *(array_2d + 5)
(array_2d[5])[6] is *(*(array_2d + 5) + 6)


So, what is array_2d converted to here? It is converted to pointer to
its first element. That is an array of 20 ints

Im sorry if i don't understand but do you mean 200 ints when you say 20
above?

No, he means 20. array_2d is an array of 10 array of 20 int. The
first element of array_2d is array_2d[0] which is itself the first
array of 20 int. There are nine more such arrays, named array_2d[1]
through array_2d[9]. All told there are 200 int but the first element
of array_2d is only the first 20 of them.
-- array2d consists of
10 of these 20-elements arrays one after the other.

okay, so in declaration:

int a[2][3];

the elements are so formatted in memory in ascending address from left
to right in page??

+===================+===================+
|+-----+-----+-----+|+-----+-----+-----+|
|| 0,0 | 0,1 | 0,2 ||| 1,0 | 1,1 | 1,2 ||
|+-----+-----+-----+|+-----+-----+-----+|
+=======================================+
OK
Writing this
type is messy in C and does not help with this exposition[1].

As per your note[1] then *(array_2d + 5) is of type int (*)[20]?
Then what is type of array_2d + 5?

No. array_2d as an expression that is not the operand of & or sizeof
operators is automatically converted to a pointer to the first element
of array_2d with type pointer to element type, effectively
&array_2d[0]. Adding an int to this value/expression does not change
its type. It is still a pointer but now it points to the sixth
element, effectively &array_2d[5]. Since the object it points to is
an array of 20 int, the expression array_2d+5 has type int(*)[20].

From there, we know that *(array_2d+5) dereferences this pointer and
must have type array of 20 int, int [20].
Now 5 gets added to that pointer. This arithmetic is done is units of
the size of the things being pointer to, in this case, 20-element int
arrays. Thus the result is a pointer that points at the 6th set of 20
ints.

[The standard does not describe it this way (in terms of sizes). It
simply says that adding /i/ to a pointer that points into an array
makes a pointer that points to the /i/th element. I described it my
way, because when that array is an array of arrays (as we have here)
the wording gets messy.]

This new pointer (array_2d + 5) has type "pointer to array of 20 int",
so applying the * to it results in a value whose type is "array of 20
int". Again, because this value is not used in one of the three
special situations, it is converted to a pointer to its first element:
in this case an int.

6 gets added to this int pointer, to give a pointer to the 7th
element in the 6th sub-array of array_2d. Applying the star, gives us
a modifiable lvalue that refers to this element (i.e. array_2d[5][6]
can be used like this: 'array_2d[5][6] = 42;' as well as like this:
'return array_2d[5][6] + 1;').

The tricky bit that array_2d[5] has array type. The value gets
converted to a pointer to array type and the arithmetic on the pointer
moves it about from one 20-element array to the next.

okay then what is the type of *(array_2d + 5) + 6? I hink it is int*?

As noted above *(array_2d+5) has type array of 20 int. It is not the
operand of & or sizeof and is therefore automatically converted to
pointer to the first element of the array with type pointer to element
type, effectively &array_2d[5][0] which has type int*. Adding an int
to it doesn't change the type. It simple points to the seventh
element of the array of 20 int. It is exactly equivalent to
&array_2d[5][6] with the same type (int*).
Also what is type of just array_2d? is it int (*)[10][20]?

As an object, array_2d has the type array of 10 array of 20 int,
written as int [10][20]. If you used array_2d as the operand of
sizeof, it would evaluate to 800, essentially 10*20*sizeof(int)
(assumed to be 4 for example purposes). As an expression that is not
the operand of & or sizeof, it is converted to a pointer as describe
above with resulting type int (*)[20].
[1] It is 'int (*)[20]'.

Thank you very much Ben. Im not able to easily understand 2D arrays like
1D ones, but i'll keep reading your notes until i figure it.


Remove del for email
 
K

Kapteyn's Star

Ben Bacarisse wrote:

Ben, im sorry for deleting your very good descriptions but someone told
me to delete anything not needed and i found everthing in your post
important so i deleted everything :)

I will recapture what i know about arrays mainly to check if im getting
it. please correct me if im wrong.

Given the declaration:

int *arrp[5][10][15];

% The object denoted by the name arrp is typed int* [5][10][15]
% sizeof arrp equals 5*10*15 * sizeof(int*)
% The expression &arrp has type int* (*)[5][10][15]
% The name arrp when not an operand of sizeof or & becomes a value
of type int* (*)[10][15] and is equal to &arrp[0]
% arrp[3] or *(arrp + 3) selects an object of type int* [10][15]
and because the expression has an array type and is not an operand
to sizeof or & it becomes a value of type int* (*)[15]
% arrp[3][4] or *(*(arr + 3) + 4) is typed int* [15] and again
becomes a value of type int**
% arrp[3][4][5] or *(*(*(arrp + 3) + 4) + 5) is a value of type int*

okay i think i can understand this stuff... :)

Now if only i can find out the common formula behind this...

So when the above array is given as an argument to a function what is
actually passed is a pointer of type int* (*)[][10][15] or
int* (*)[10][15] which should be used with either index or pointer
notation.

Will doing ***arr = 0 set the element arr[0][0][0] to 0 inside the
function?

Thanks for youe post...
 
K

Kapteyn's Star

Barry said:
int array_2d[10][20] = { ... };
No, he means 20. array_2d is an array of 10 array of 20 int. The
first element of array_2d is array_2d[0] which is itself the first
array of 20 int. There are nine more such arrays, named array_2d[1]
through array_2d[9]. All told there are 200 int but the first element
of array_2d is only the first 20 of them.

Thank you very much for your clear descriptions Barry. I have to delete
most of them in this reply because my news server doesnt allow me to
post articles with more than 80% quotes.
 
K

Kapteyn's Star

Barry said:
On Fri, 18 Jul 2008 17:45:19 +0530, Kapteyn's Star


It would have done this except that there is no int* in your call to
fread. By putting the & in front of the i, you have created an
expression of type int** and also rendered the code unusable. It
effectively says to read n items, each of which has size of int, into
a single variable which has size of int*. Even if n is one, it is
possible for sizeof(int) to be greater than sizeof(int*) and the code
would invoke undefined behavior. Chances are you really meant to say
read n items of size int into a series of objects of type int, the
first of which is pointed to by i. The code for this is
fread(i, sizeof *i, n file);
and of course i must be assigned a suitable value before the call.

If you want to fread into a declared object, use the &. If you want
to fread into whatever the object points to, don't.

Yes you're spot on! What a silly error to make... thanks anyway.
 
H

Harald van Dijk

I will recapture what i know about arrays mainly to check if im getting
it. please correct me if im wrong.

Given the declaration:

int *arrp[5][10][15];

So when the above array is given as an argument to a function what is
actually passed is a pointer of type int* (*)[][10][15] or int*
(*)[10][15] which should be used with either index or pointer notation.

A pointer of type int*(*)[10][15] will be passed. int*(*)[][10][15] is a
different type not compatible with &arrp[0], but compatible with &arrp.
Will doing ***arr = 0 set the element arr[0][0][0] to 0 inside the
function?

Yes, when arr is a function parameter declared as int*(*arr)[10][15] or
equivalent, and the function argument is arrp as declared above, ***arr
and arr[0][0][0] mean the same thing, and setting either to 0 modifies
arrp[0][0][0].
 
B

Barry Schwarz

Ben Bacarisse wrote:

Ben, im sorry for deleting your very good descriptions but someone told
me to delete anything not needed and i found everthing in your post
important so i deleted everything :)

I will recapture what i know about arrays mainly to check if im getting
it. please correct me if im wrong.

Given the declaration:

int *arrp[5][10][15];

% The object denoted by the name arrp is typed int* [5][10][15]
% sizeof arrp equals 5*10*15 * sizeof(int*)
% The expression &arrp has type int* (*)[5][10][15]
% The name arrp when not an operand of sizeof or & becomes a value
of type int* (*)[10][15] and is equal to &arrp[0]
% arrp[3] or *(arrp + 3) selects an object of type int* [10][15]
and because the expression has an array type and is not an operand
to sizeof or & it becomes a value of type int* (*)[15]
% arrp[3][4] or *(*(arr + 3) + 4) is typed int* [15] and again
becomes a value of type int**
% arrp[3][4][5] or *(*(*(arrp + 3) + 4) + 5) is a value of type int*

okay i think i can understand this stuff... :)

Now if only i can find out the common formula behind this...

So when the above array is given as an argument to a function what is
actually passed is a pointer of type int* (*)[][10][15] or

This is not a valid type. For purposes of declaring the parameter,
you could use int* [][10][15], note the omitted (*).
int* (*)[10][15] which should be used with either index or pointer

This is the type that the function actually receives. The two
declarations are identical when used to describe a parameter.
notation.

Will doing ***arr = 0 set the element arr[0][0][0] to 0 inside the
function?

Yes. Since you already know (from your fifth % above) that
array[index] is defined as *(array+index), repeated decomposition
yields
arr[0][0][0] is defined as *(arr[0][0] +0)
which in turn is defined as *(*(arr[0]+0)+0)
which in turn is defined as *(*(*(arr+0)+0)+0)
and since adding 0 changes nothing this is *(*(*(arr)))
and the parentheses are superfluous you get ***arr.
Thanks for youe post...


Remove del for email
 
H

Harald van Dijk

So when the above array is given as an argument to a function what is
actually passed is a pointer of type int* (*)[][10][15] or

This is not a valid type. [...]

Yes, it is. It's a pointer to an array of unspecified length. You are
allowed to do that.
 
D

David Thompson

Thanks Richard. Is it true that fread() and fwrite must only be used with
binary mode files, or can we use them with text files too as long as
understood that '\n' may be converted from more than one byte?

(Since no prompter person has taken care of this...)

The latter. All standard-C I/O, both formatted and unformatted, is
defined to be done 'as if' a char at a time using fgetc/fputc (or *wc
for the wide versions), although in practice implementations will use
code more efficient than actually doing a function call per char.

However, binary file formats rarely contain data than can easily and
robustly be parsed with fscanf, and only occasionally that can easily
be created with fprintf. (Arguably fscanf isn't very robust even on
text files, but I'm saying even worse on binary.) And common text file
formats don't consist of known size elements that can easily be
handled with fread/fwrite -- with one notable exception: if you want
to slurp the whole file into a memory buffer and work on it there,
and/or build the whole contents in memory and (then) spew them out,
fread and fwrite are quite appropriate.

- formerly david.thompson1 || achar(64) || worldnet.att.net
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
474,145
Messages
2,570,827
Members
47,373
Latest member
Desiree036

Latest Threads

Top