compiling error

K

Kapteyn's Star

Hi newsgroup

The program here given is refused by GCC with a error i cannot
understand. It says
rnd00.c: In function ‘main’:
rnd00.c:26: error: expected expression before ‘]’ token

How to make it compile? I also tried buf[10] but that gives "segmentation
fault". Thanks in advanced.

/* scanf 10 random integers from /dev/random */
#include <stdio.h>

void open_file(FILE *f)
{
f= fopen("/dev/random", "r");
}

void read_values(FILE *f, int buf[], int count)
{
do
{
--count;
fread((void*)&buf[count], sizeof(int), 1, f);
}
while(count > 0);
}

int main()
{
int buf[10];
int count= 10;
FILE *f;

open_file(f);
read_values(f, buf[], count);
do
{
--count;
printf("%d ", buf[count]);
}
while(count > 0);
return 0;
}
 
K

Kapteyn's Star

Richard said:
Kapteyn's Star said:
Hi newsgroup

The program here given is refused by GCC with a error i cannot
understand. It says
rnd00.c: In function ?main?:
rnd00.c:26: error: expected expression before ?]? token

How to make it compile? I also tried buf[10] but that gives
"segmentation fault". Thanks in advanced.

/* scanf 10 random integers from /dev/random */ #include <stdio.h>

void open_file(FILE *f)
{
f= fopen("/dev/random", "r");

This won't do what you think. If you want a function to change the value
of an object, you must pass to that function the address of the object.
Alternatively, you can get the function to return the new value of the
object, and pick it up in the caller, as shown:

FILE *open_file()
{
return fopen("/dev/random", "r");
}

usage: fp = open_file();

If you want to do it the parameter way, you need to do this:

void open_file(FILE **f)
{
*f = fopen("/dev/random", "r");
}

Usage: open_file(&fp);

oops I forget constantly that C does pass by value for functions, curse
of having learned Pascal in school :)
Remember that fopen will return a null pointer if it fails to open the
file.

Okay. I ommited checking fopen() because /dev/random exists here. But i
see your point, it might be absent under older kernels.
}

void read_values(FILE *f, int buf[], int count) {
do
{
--count;
fread((void*)&buf[count], sizeof(int), 1, f);

Simpler:
fread(&buf[count], sizeof buf[count], 1, f);

I thought that a typecast is needed when converting between different
typed pointers...
or even
fread(buf + count, sizeof buf[count], 1, f);

This is neat! I still not getting the hang of pointer arithmetics. :(
But sizeof without parenthesis just feels weird. I thought it wont
compile but it does! So much to learn in c...
int main()
{
int buf[10];
int count= 10;
FILE *f;

open_file(f);
read_values(f, buf[], count);

This should be: read_values(f, buf, count);

Okay arrays when passed to function should not have the index but the
index is needed when in the prototype? Noted.

Thanx to you and Ben... program works now!
 
K

Kapteyn's Star

Ben said:
Kapteyn's Star <[email protected]>
writes:


In addition to the other comments, that should be "rb".

I read in books that in Linux/UNIX there is no difference in text and
binary formats...that was why i left out the b. So i take it that b must
always be used?? Thanx Ben.
 
K

Kapteyn's Star

Richard said:
Kapteyn's Star said:
Richard said:
Kapteyn's Star said:

}

void read_values(FILE *f, int buf[], int count) {
do
{
--count;
fread((void*)&buf[count], sizeof(int), 1, f);

Simpler:
fread(&buf[count], sizeof buf[count], 1, f);

I thought that a typecast is needed when converting between different
typed pointers...

If you need a cast, the chances are good that the conversion isn't
appropriate anyway. In this case, fread takes void * for the first arg,
and the language guarantees that a conversion will be provided between
void * and any object-pointer type, in either direction, so you don't
need the cast at all.

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??
If you specify a type - sizeof(int) - you need the parentheses, but
specifying a type is almost always the Wrong Thing. Types can change.
Using sizeof on an expression is far better, because if/when you change
the type, you don't have to worry about the sizeof because it will
already "know", so to speak. If you did sizeof(int), however, and later
switched to, say, double, you'd have had to change the sizeof to
sizeof(double) - a maintenance task that is easily overlooked by
mistake.

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.
You can't pass an array to a function. But when you try, what actually
happens is that C interprets the array name as if it were a pointer to
the first element of the array. This is because C is pass-by-value, and
arrays don't have values as such. In practice, it's exactly what you
want, most of the time, so no harm done.

I think i can understand... so arrays are not copied on the stack when we
give them as args to a function but a pointer to it is passed instead. So
given:

int arr[5];
func(arr);

in func() *arr is the same as arr[0] and &arr == &arr[0]?
should not have the index but the
index is needed when in the prototype? Noted.

Yes, the type decoration for arrays is required in the declaration,
whether it's a function declaration or object declaration or whatever.
(Of course, in a function declaration it isn't really an array - T foo[]
is understood by the compiler to mean T *foo, which is a little
confusing in my opinion, but that's C for you.)

which usage is better in function declarations T *arr or T arr[]? but
there is no difference in actual functions right? That is, everything I
can do with func(T arr[]); can be done with func(T *arr); also??
But in usage, you just need the name of the object, plus any operators
that you want to apply to that object. Note that, sometimes, you do want
the [] operator, e.g. if you are accessing a value in the array, you
need to know which value you are accessing: as in...

printf("%d\n", buf[count]);

Note that this is precisely equivalent to:

printf("%d\n", *(buf + count));

A relatively obscure equivalence, but it should bring home to you that
buf doesn't need to have a [] constantly nailed to its behind. :)

Okay I think im getting the hang of all this. six months back I tried to
learn C from Teach Yourself C in 24 hours but it was too boring :) Now I
have got The C Programming Language which was highly recommanded in this
group...the problems are very interesting but some are tough also!

Thanks for your response.
 
K

Kapteyn's Star

A small thing confuses me. man urandom says

When read, the /dev/random device will only return random bytes...

So is it correct of me to read from /dev/random int values? Or i should
have read instaed of 10 int 40 char values and then cast them to 10 ints??

can i also do the below to get random real numbers?

float a[5];
fread(a, sizeof a[0], 5, dev_random);

is this also the same as?

fread(a, sizeof a, 1, dev_random);

are these all okay?

thanks for any help.
 
K

Keith Thompson

Kapteyn's Star said:
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??

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.

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.)

And of course the fourth specifies the stream you want to read from.
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*.

And as for "sizeof" without parentheses looking funny, think of it
this way. "sizeof" is an operator, not a function. It happens to be
the only operator in C whose symbol is a keyword (which looks like an
identifier, which looks like it could be a function name) rather than
one or more punctuation marks. Operators don't require parentheses on
their operands (you can write -x, you don't have to write -(x)). The
sizeof operator is no different; you can write sizeof x; you don't
have to write sizeof(x). Though you can add parentheses if you like,
and in some cases it might be necessary for disambiguation.

It's similar in this way to the return statement. You can write
"return x;" rather than "return(x);", because "return" isn't a
function. (It's not an operator either; it's a special form of
statement.) You can write "return(x);" if you really want to, but the
parentheses are just part of an ordinary parenthesized expression, not
part of the syntax of the return statement.

*But* there's another form of the "sizeof" operator, one whose operand
is a type name rather than an expression. This form of "sizeof" is
what's weird and exceptional. The type name is enclosed in
parentheses, but the parentheses aren't the same as the parentheses
you see on a function call; they're specified by an entirely different
syntax rule. And they're necessary to avoid ambiguity. You can think
of ``sizeof ( type-name )'' as a special distinct form of expression
-- and one that you really don't need to use very often. (The use of
parentheses on a cast is a similar case of surrounding a type name
used in an expression with parentheses to avoid ambiguity.)
I think i can understand... so arrays are not copied on the stack when we
give them as args to a function but a pointer to it is passed instead.

Almost, but not quite. I think it's time to bring out (drum roll)
The Rule.

You *can't* give an array as an argument to a function. You can try,
but it's just not possible in C. (Well, you can wrap the array in a
struct and pass the struct, but we'll ignore that; you can't do it
directly.)

Let's forget about functions, parameters, and arguments for a moment,
and just talk about arrays and pointers.

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.

So, when you call a function like:
given:

int arr[5];
func(arr);

the expression "arr" is of array type, and its context isn't one of
the three exceptions, so it's implicitly converted to the address of
arr[0], of type int*. This conversion has nothing to do with the fact
that it's a function argument; the same thing would happen in any
context other than the Big Three.

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.

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);

The "[]" form can be used to document the fact that you expect to be
passing (the address of the first element of) an array to the
function. But I prefer the "*" form, since it says what it really
means.

An excellent resource for this kind of thing is section 6 of the
comp.lang.c FAQ said:
in func() *arr is the same as arr[0] and &arr == &arr[0]?

Assuming func's parameter was declared as "int *arr" or "int arr[]",
then yes, *arr is the same as arr[0]. But &arr and &arr[0] are not
the same thing. Remember that, inside func, arr is a pointer object
(a parameter); &arr is the address of that pointer object. &arr[0];
is the address of the first (zeroth?) element of the array to whose
first element arr points.

arr == &arr[0] is correct, though.

And remember that the address of an array and the address of its first
element are two different things. They both refer to the same
location in memory, but they're of different types.

[snip]
 
H

Harald van Dijk

You *can't* give an array as an argument to a function. You can try,
but it's just not possible in C.

Are you allowed to pass an array rvalue to a variadic function in C90?
 
H

Harald van Dijk

No, it's still converted to a pointer value.

As far as I was aware, array rvalues are never converted to pointers in
C90, and that conversion is one of the changes C99 made. If you say that
the conversion does exist in C90, could you also say in what other
contexts it can be performed?
 
J

Joachim Schmitz

Richard said:
Kapteyn's Star said:


Right. But on other platforms, the difference is real.


It's a great habit to get into. One day, they might pay you huge
amounts of money to work on a W. To work on a Wi. A W. A <cough cough
cough> WINdows system. And on that system, the difference is real and
significant. When opening binary files under Linux or Unix there is
no harm in adding the "b" (the Standard requires it to be supported),
so for the sake of one extra letter you keep yourself in good shape
for when, some day, you have to get your code to run under some other
system.
But Windows doesn't have a /dev/random, so you'd have to modify the code
anyway...
/dev is a UNIXism (and /dev/radnam non portable at all), so it should be
safe to drop the b.

Bye, Jojo
 
K

Keith Thompson

Richard Heathfield said:
Kapteyn's Star said: [...]
can i also do the below to get random real numbers?

float a[5];
fread(a, sizeof a[0], 5, dev_random);

Only if you can guarantee that every bit pattern represents a valid float
value (which you can't, because they don't, on most systems).
is this also the same as?

fread(a, sizeof a, 1, dev_random);

Yes, and unfortunately it's equally broken. You're okay to do this with
ints, but not with floating point.

Strictly speaking, it's not safe with ints either. Integer types
(other than the character types), just like floating-point types, are
allowed to have trap representations. They're just less likely to do
so; on most systems, and quite possibly on all systems that have
/dev/random, all possible bit patterns represent valid and distinct
integer values.

To be safe, read data from /dev/random as a stream of unsigned char
values, and construct an integer value from the bytes (say, by
shifting and or'ing).
 
K

Keith Thompson

Joachim Schmitz said:
But Windows doesn't have a /dev/random, so you'd have to modify the code
anyway...
/dev is a UNIXism (and /dev/radnam non portable at all), so it should be
safe to drop the b.

But why would you want to? It's a binary file; you should use "rb" to
read from it. Using "r" (text mode) is, IMHO, a bug that doesn't
cause any symptoms.

Also, think about running the program under Windows with some sort of
emulation for /dev/random. A concrete example: Cygwin provides
/dev/random, and can be configured to use Windows style text files
(though it normally isn't). It's entirely possible in such an
environment that a "\r\n" sequence read from /dev/random will be
translated to "\n", or, worse, that control-Z will trigger an
end-of-file condition.

Use "r" for text files, "rb" for binary files.
 
K

Keith Thompson

Harald van Dijk said:
As far as I was aware, array rvalues are never converted to pointers in
C90, and that conversion is one of the changes C99 made. If you say that
the conversion does exist in C90, could you also say in what other
contexts it can be performed?

I think I didn't pay close enough attention to the word "rvalues".

I'm not sure what you mean, but I'm not aware of any such change
between C90 and C99. Can you give an example where an array rvalue
isn't converted to a pointer value in C90 (other than the usual 3
exceptions in The Rule)? Most array expressions are lvalues; I'm
having trouble thinking of a plausible case that isn't.

Hmm. I vaguely remember a case involving a function returning a
struct with an array member. Is that what you're referring to?

Note that C doesn't define the term "rvalue"; a footnote says that
it's merely the "value of an expression". I'd guess that you mean an
expression that's not an lvalue, but I'd appreciate a clarification.
 
L

lawrence.jones

Harald van D??k said:
As far as I was aware, array rvalues are never converted to pointers in
C90, and that conversion is one of the changes C99 made. If you say that
the conversion does exist in C90, could you also say in what other
contexts it can be performed?

You're conflating array rvalues with rvalue arrays. :)

The original discussion was about passing an array as a function
parameter (which you can't do in C). That's using an array (which is an
lvalue) as an rvalue, which is perfectly valid in either variant of C.
The compiler implicitly converts the array into a point to its first
element. This implicit conversion is why you can't pass the array
itself; there's no way to disable the conversion.

What you're talking about is rvalue arrays (i.e., an array that is a
member of a non-lvalue struct, such as the return value from a
function). In C90, the implicit conversion was not done if the array
was not an lvalue, making such arrays essentially useless. C99 fudged
the rules to allow the conversion to occur, even though it doesn't make
much sense philosophically, because it useful (and does make sense) in
practice.
 
F

Flash Gordon

Kapteyn's Star wrote, On 15/07/08 16:48:
Richard said:
Kapteyn's Star said:
Richard Heathfield writes:

Kapteyn's Star said:

}

void read_values(FILE *f, int buf[], int count) {
do
{
--count;
fread((void*)&buf[count], sizeof(int), 1, f);
Simpler:
fread(&buf[count], sizeof buf[count], 1, f);
I thought that a typecast is needed when converting between different
typed pointers...
If you need a cast, the chances are good that the conversion isn't
appropriate anyway. In this case, fread takes void * for the first arg,
and the language guarantees that a conversion will be provided between
void * and any object-pointer type, in either direction, so you don't
need the cast at all.

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??

It does not know what is pointed to nor does it need to know. All it
knows is the size of an element and the number of elements and it only
knows that because you explicitly tell it. freed just blindly reads in
bytes.
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.

Normally it is far more important that you have the size of the object
than the size of a specific type. As Richard says, what happens if you
change the type?
I think i can understand... so arrays are not copied on the stack when we
give them as args to a function but a pointer to it is passed instead.

Not quite, a pointer to the first element of the array is passed.
So
given:

int arr[5];
func(arr);

in func() *arr is the same as arr[0] and &arr == &arr[0]?

*arr is the same as arr[0], however &arr is of a different type to
&arr[0]. &arr is a signpost pointing at the street you live in but does
not indicate a specific house (the array) where as &arr[0] is your
finger pointing at the first house in your street (the first element of
the array).

I suggest you go over to http://c-faq.com/ and read the sections on
arrays and pointers.
should not have the index but the
index is needed when in the prototype? Noted.
Yes, the type decoration for arrays is required in the declaration,
whether it's a function declaration or object declaration or whatever.
(Of course, in a function declaration it isn't really an array - T foo[]
is understood by the compiler to mean T *foo, which is a little
confusing in my opinion, but that's C for you.)

which usage is better in function declarations T *arr or T arr[]?

It is a matter of style and nothing more.
but
there is no difference in actual functions right? That is, everything I
can do with func(T arr[]); can be done with func(T *arr); also??

Since the two mean *exactly* the same thing, yes.

Okay I think im getting the hang of all this. six months back I tried to
learn C from Teach Yourself C in 24 hours but it was too boring :) Now I
have got The C Programming Language which was highly recommanded in this
group...the problems are very interesting but some are tough also!

If the problems were too easy then there would not be much point to them!

When you have a problem you should check the comp.lang.c FAQ at
http://c-faq.com/ to see if you can find the answer. If you cannot find
the answer, or find the right question but cannot understand the answer
then ask. This will save *you* time since you won't have to wait for
someone to see and have time to reply to your question!
 
F

Flash Gordon

Richard Heathfield wrote, On 15/07/08 18:40:
Kapteyn's Star said:
fread(a, sizeof a[0], 5, dev_random);
is this also the same as?

fread(a, sizeof a, 1, dev_random);

Yes,

<snip>

No, they are *not* quite the same, in particular the return value is
different (and should be checked as Richard knows).

Consider:
size_t count = fread(arr, sizeof arr[0], 5, file);
If an error (or end-of-file) is encountered after reading two elements
of arr count will be set to 2 and you will know you have at least some data.

Now consider:
size_t count = fread(arr, sizeof arr, 1, file);
If an error (or end-of-file) is encountered after reading two elements
of arr count will be set to 0 and you won't know that you have at least
some data.
 
H

Harald van Dijk

I think I didn't pay close enough attention to the word "rvalues".

I'm not sure what you mean, but I'm not aware of any such change between
C90 and C99. Can you give an example where an array rvalue isn't
converted to a pointer value in C90 (other than the usual 3 exceptions
in The Rule)? Most array expressions are lvalues; I'm having trouble
thinking of a plausible case that isn't.

Hmm. I vaguely remember a case involving a function returning a struct
with an array member. Is that what you're referring to?

That's one way to get a non-lvalue array, yes. Another is to use the
result of an assignment or ?:.

struct S { int array[2]; };
struct S f(void);
int main(void) {
printf("%d\n", f().array[0]);
return 0;
}

This is a valid translation unit in C99, but not in C90, because in C90,
f().array is not converted to a pointer, and you cannot add 0 to an array.

For a more complete example of an array being passed (at least, where I
think an array is supposed to be passed):

#include <stdio.h>
#include <stdarg.h>

typedef int array_t[100];

struct S {
array_t array;
};

void f(int ignore, ...) {
va_list ap;
va_start(ap, ignore);
va_arg(ap, array_t);
printf("%d\n", va_arg(ap, int));
va_end(ap);
}

struct S g(void) {
static struct S s;
return s;
}

int main(void) {
f(0, g().array, 1);
return 0;
}

Is this program valid C90? If not, is the behaviour undefined, or are any
constraints violated? Compilers vary in their results. Some refuse to
compile the program. Others compile it, and the output is 1. Yet there are
also that compile it, and the resulting program outputs 0.

(_If_ the program is valid C90, then this is a very strange case, and I
don't believe anyone in their right mind would seriously make use of it.)
Note that C doesn't define the term "rvalue"; a footnote says that it's
merely the "value of an expression". I'd guess that you mean an
expression that's not an lvalue, but I'd appreciate a clarification.

Yes, I meant a non-lvalue expression.
 
C

Chris Torek

(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.)

I believe this is wrong: fread() will, in this case, overwrite one
of the four bytes making up the fourth array element. (The reason
the C Standard permits this is to allow implementations to be
"lazy". If they had to avoid touching part of an element, they
would have to make sure that there were enough bytes in the stream
to fill in a complete element. This becomes "arbitrarily hard" as
the element size gets large, especially if the stream is connected
to something other than an on-disk file. For instance, if the
stream is receiving input over a TCP connection, and you ask to
read one or more elements of size 10 million bytes each, the
implementation would have to "save up" nearly 10 MB before writing
it all, since it has no way of knowing whether the TCP stream is
going to fail in mid-read.)

The main thing the separate size argument does is cause fread()
to return a count of whole objects filled in, rather than a
count of bytes, saving you the division:

n_got = fread(base_of_array, n_desired, size_of_each, stream);

vs:

n_got =
fread(base_of_array, n_desired * size_of_each, 1, stream) /
size_of_each;

These two calls do exactly the same thing, but force you to write
the multiplication and division expressions.
 
R

Richard Tobin

I believe this is wrong: fread() will, in this case, overwrite one
of the four bytes making up the fourth array element.

Three bytes of it, surely.

-- Richard
 

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

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,372
Latest member
LucretiaFo

Latest Threads

Top