K
Kapteyn's Star
Firstly thank you so much for your detailed advices Keith! I am not able
to understand now all you say but i have saved your post for reading
later. I hope you wont mind?
okay, so inside fread() the voip pointer will be typecast to unsigned
char pointer when writing read bytes into the buffer correct?
So the point of having fread() take parametres for no. and size of
elements is to tailor it to read to various types of arrays, even though
it actually writes into teh buffer through an unsigned char pointer cast?
am I confusing things here?
If I get all this right then when we need to fill an array of N elemenets
it's better to tell fread() to read N elements than 1 big read for the
entire array. This way if fread() only reads partially, then returned
value will not be 0 and we can find out how many elements have been
stored.
Okay I understand but when i am reading codes that have this statement:
ptr= (ptr*)malloc(N * sizeof(type));
I can instantly know what value the product is because i have memorised
the default sizes for int, float and so on. But with sizeof *ptr i have
to jump to ptr's declaration and then multiply the type's size with N.
But i realise that your style is auto-correcting itself to changes. taht
is better code...
Im sorry for snipping your excellent explanations for sizeof op. not
needing parenthesis except with types and return statement not needing
parenthisis also... but Pan is not allowing me to post articles with
"mostly quotes text"...
Re. operators not needing brackets doesnt the cast op. need it? Atleast
my K&R book lists (cast) is op. the precedence list on chapter 2.
Also the switch condition also doesnt need parenthesis like return?
I didnt realise that string constants were expressions of pointer type
except with initialising arrays when its an array type. I though string
constants only existed in the source code...
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);
i think im going wrong here but i wrote a program to test it. here is
code and o/p seems identical for both assignments:
#include <stdio.h>
int main()
{
int array_2d[10][20];
int elem, i0, i1;
for(i0= 0; i0 < 10; ++i0)
{
for(i1= 0; i1 < 20; ++i1)
{
array_2d[i0][i1]= i0 + i1;
}
}
for(i0= 0; i0 < 10; ++i0)
{
for(i1= 0; i1 < 20; ++i1)
{
elem= array_2d[i0][i1];
printf("[%d][%d] = %d ", i0, i1, elem);
elem= *(*(array_2d + i0) + i1);
printf("%d\n", elem);
}
}
return 0;
}
../a.out
[0][0] = 0 0
[0][1] = 1 1
[0][2] = 2 2
[0][3] = 3 3
[0][4] = 4 4
[0][5] = 5 5
[0][6] = 6 6
[0][7] = 7 7
[0][8] = 8 8
[0][9] = 9 9
[0][10] = 10 10
[0][11] = 11 11
[0][12] = 12 12
[0][13] = 13 13
[0][14] = 14 14
[0][15] = 15 15
[0][16] = 16 16
[0][17] = 17 17
[0][18] = 18 18
[0][19] = 19 19
[1][0] = 1 1
[1][1] = 2 2
[1][2] = 3 3
....
[9][19] = 28 28
Okay so does
void func(int arr[][]);
mean this?
void func(int *arr[]);
im having trouble scaling my understand of 1D arrays to 2D and above...
Thanks. I will check it out.
to understand now all you say but i have saved your post for reading
later. I hope you wont mind?
There's no magic. fread() *doesn't* know that you've passed it an
integer array (and in fact you haven't; see below).
The first argument to fread() is normally the address of an array, or of
the first element of an array, which will be converted to void* (a raw
address). This tell fread() where in memory your object is, but nothing
else about it.
okay, so inside fread() the voip pointer will be typecast to unsigned
char pointer when writing read bytes into the buffer correct?
The second and third arguments are the size in bytes of each element of
your array, and the number of elements you want to read into. This
tells fread() how much data to read; it's the second and third arguments
multiplied together to yield the size in bytes of the array.
(So why not just use a single size argument? Because fread() reads
whole elements at a time. If you ask it to read 10 4-byte elements from
a file that only has 15 remaining byte, it will only set the first 3
4-byte elements of your array; it won't touch the 4th element of your
array.)
So the point of having fread() take parametres for no. and size of
elements is to tailor it to read to various types of arrays, even though
it actually writes into teh buffer through an unsigned char pointer cast?
am I confusing things here?
If I get all this right then when we need to fill an array of N elemenets
it's better to tell fread() to read N elements than 1 big read for the
entire array. This way if fread() only reads partially, then returned
value will not be 0 and we can find out how many elements have been
stored.
I see what you say. But sizeof(type) is understandable when i look at
it but sizeof expression means i have to figure out the expresson and
find out to which type it belongs.
Not necessarily; the *compiler* has to figure that out. Typically the
expression is the name of an object. You usually need the size of that
object, whatever type it happens to be. And you don't necessarily have
to know the type of the object to understand why you need its size.
some_type arr[N];
fread(arr, sizeof arr[0], N, some_file);
To know that the fread call's arguments are correct, you don't need to
know the type of arr, you just need to know that it's an N-element array
of *something*.
Okay I understand but when i am reading codes that have this statement:
ptr= (ptr*)malloc(N * sizeof(type));
I can instantly know what value the product is because i have memorised
the default sizes for int, float and so on. But with sizeof *ptr i have
to jump to ptr's declaration and then multiply the type's size with N.
But i realise that your style is auto-correcting itself to changes. taht
is better code...
Im sorry for snipping your excellent explanations for sizeof op. not
needing parenthesis except with types and return statement not needing
parenthisis also... but Pan is not allowing me to post articles with
"mostly quotes text"...
Re. operators not needing brackets doesnt the cast op. need it? Atleast
my K&R book lists (cast) is op. the precedence list on chapter 2.
Also the switch condition also doesnt need parenthesis like return?
When you have an expression of array type (such as the name of an array
object), that expression is, *in most contexts*, immmediately and
implicitly converted to a pointer to (equivalently: the address of) the
first element of the array. The only exceptions to this are: (1) when
the array expression is the operand of a "sizeof" operator (so "sizeof
arr" gives you the size of the entire array, not the size of a pointer);
(2) when the array expression is the operand of a unary "&" (so "&arr"
gives you the address of the array, not of its first element); and (3)
when the array expression is a string literal used in an initializer for
an array object. The last case is slightly obscure; it means that this:
char s[] = "hello";
initializes the array s with { 'h', 'e', 'l', 'l', 'o' '\0' }, not with
a pointer value.
I didnt realise that string constants were expressions of pointer type
except with initialising arrays when its an array type. I though string
constants only existed in the source code...
Here's an interesting point: The rules for multidimensional arrays are a
direct consequence of this. The standard needn't have mentioned
multidimensional arrays at all. They're implied by the rules for
one-dimensional arrays, and for array-to-pointer conversion. Given:
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);
i think im going wrong here but i wrote a program to test it. here is
code and o/p seems identical for both assignments:
#include <stdio.h>
int main()
{
int array_2d[10][20];
int elem, i0, i1;
for(i0= 0; i0 < 10; ++i0)
{
for(i1= 0; i1 < 20; ++i1)
{
array_2d[i0][i1]= i0 + i1;
}
}
for(i0= 0; i0 < 10; ++i0)
{
for(i1= 0; i1 < 20; ++i1)
{
elem= array_2d[i0][i1];
printf("[%d][%d] = %d ", i0, i1, elem);
elem= *(*(array_2d + i0) + i1);
printf("%d\n", elem);
}
}
return 0;
}
../a.out
[0][0] = 0 0
[0][1] = 1 1
[0][2] = 2 2
[0][3] = 3 3
[0][4] = 4 4
[0][5] = 5 5
[0][6] = 6 6
[0][7] = 7 7
[0][8] = 8 8
[0][9] = 9 9
[0][10] = 10 10
[0][11] = 11 11
[0][12] = 12 12
[0][13] = 13 13
[0][14] = 14 14
[0][15] = 15 15
[0][16] = 16 16
[0][17] = 17 17
[0][18] = 18 18
[0][19] = 19 19
[1][0] = 1 1
[1][1] = 2 2
[1][2] = 3 3
....
[9][19] = 28 28
Another rule (which, IMHO, just causes confusion) is that in a parameter
declaration, an array declaration is really a pointer declaration. This
isn't a run-time conversion, it's a compile-time re-interpretation. So
this:
void func(int arr[]);
really *means* this:
void func(int *arr);
Okay so does
void func(int arr[][]);
mean this?
void func(int *arr[]);
im having trouble scaling my understand of 1D arrays to 2D and above...
An excellent resource for this kind of thing is section 6 of the
comp.lang.c FAQ, <http://www.c-faq.com>.
Thanks. I will check it out.