Keith Thompson writes:
> Kapteyn's Star <remove_digits_for_email_7Kapteyns3.Star@g0m8ai2l. 9com>
> writes: [...]
>> One small question. If fread() takes a void pointer then how does it
>> know that what I actually pass in an integer array? Will it figure it
>> out from the sizeof argument or is some magic going on??
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?
> 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.
--
Kapteyn's Star