Inconsistent

J

jimbo

Could someone comment on this code please.

1. Are the comments in it correct?

2. Why does sizeof(arr) not work consistently in C? In someFunction()
sizeof(arr) means sizeof(&arr[0]) in main. The compiler knows how big arr
is, so why the difference - esp. as it would be v.useful if sizeof(arr)
worked in someFunction as it does in main - so you could use sizeof(arr) in
the conditional bit of,say, a for loop in someFunction for example?

3. Why doesn't C allow testFunction to be declared char [] testFunction -
seems to me that if it did you could get away with knowing less about
pointers, and it seems as though again that C is incosistent, i.e., you
don't have to declare testFunction's parameter as char *. Surely, the
compiler should know that char [] someFunction actually means char *
someFunction??

char * testFunction(char []);

int main(void)
{
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

/* Ouput the sizeof the array. And the size of a pointer to it. */
printf("main() sizeof arr = %d\n", sizeof(arr));
printf("main() sizeof arr = %d\n", sizeof(&arr[0]));

/* Pass it on to the function where we'll do some other emaningless
things.*/
testFunction(arr);
return 0;
}


/* Can't declare testFunction as char [] testF...() - even though the
compiler knows that array's are passed by address.*/

/* The size is ignored - and can't be checked anyway.*/
char * testFunction(char arr[500])
{
int n;

/* Same sizeof line of code that was in main() - note here that it
output the size of a pointer!*/
printf("sizeof arr = %d\n", sizeof(arr));

return arr;
}
 
F

Flash Gordon

jimbo said:
Could someone comment on this code please.

1. Are the comments in it correct?

2. Why does sizeof(arr) not work consistently in C?

It *does* work consistently.
> In someFunction()
sizeof(arr) means sizeof(&arr[0]) in main.

This is the problem, you haven't understood that you don't actually pass
the array (C is not Pascal) what you pass is a pointer to the first
element of the array. This is a FAQ, see
http://www.eskimo.com/~scs/C-faq/q6.21.html and
http://www.eskimo.com/~scs/C-faq/q6.21.html
> The compiler knows how big arr
is, so why the difference - esp. as it would be v.useful if sizeof(arr)
worked in someFunction as it does in main - so you could use sizeof(arr) in
the conditional bit of,say, a for loop in someFunction for example?

It can't know in general, because you might write the function in one
translation unit and the, 25 years later, write another translation unit
that calls the first passing it an array of a different size.
3. Why doesn't C allow testFunction to be declared char [] testFunction -

Because that is the way it is defined.
seems to me that if it did you could get away with knowing less about
pointers,

For good or ill programming in C really requires an understanding of
pointers, because for the vast majority of non-trivial problems you will
end up using them.
> and it seems as though again that C is incosistent, i.e., you
don't have to declare testFunction's parameter as char *. Surely, the
compiler should know that char [] someFunction actually means char *
someFunction??

If both were valid they would mean different things. One would mean
returning an array, which C does not allow, whilst the other does mean
returning a pointer to char.
char * testFunction(char []);

int main(void)
{
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

Never lie to the compiler. It *will* get its revenge one day, possibly
by causing your application to fail miserable in front of a massive
potential customer causing your company not to get the contract it was
relying on, with the result of you being sacked for incompetence. In
this case I believe it is a constraint violation, because the standard says:
| No initializer shall attempt to provide a value for an object not
| contained within the entity being initialized.
So the compiler is *required* to complain at you, and if the compiler
chooses to produce an executable after complaining the program is
allowed to do anything at all since it is *not* a valid C program.
/* Ouput the sizeof the array. And the size of a pointer to it. */
printf("main() sizeof arr = %d\n", sizeof(arr));

If you are going to use printf you should include stdio.h because
varidac functions *require* a prototype to be in scope when you call
them or you invoke undefined behaviour and the program is allowed to do
anything at all. (you can provide a prototype manually, but that would
be a very stupid thing to do).
printf("main() sizeof arr = %d\n", sizeof(&arr[0]));

/* Pass it on to the function where we'll do some other emaningless
things.*/
testFunction(arr);
return 0;
}


/* Can't declare testFunction as char [] testF...() - even though the
compiler knows that array's are passed by address.*/

No, this is wrong. Arrays are not passed at all, a pointer to the first
element is passed.
/* The size is ignored - and can't be checked anyway.*/
char * testFunction(char arr[500])
{
int n;

/* Same sizeof line of code that was in main() - note here that it
output the size of a pointer!*/
printf("sizeof arr = %d\n", sizeof(arr));

That is because it *is* outputting the size of a pointer.
return arr;

Here you are *not* returning an array, you are returning a pointer.
 
C

Christopher Benson-Manica

jimbo said:
1. Are the comments in it correct?

You forgot the part about "Never do this."
2. Why does sizeof(arr) not work consistently in C?

Because it doesn't work the way you seem to think it does.
In someFunction()
sizeof(arr) means sizeof(&arr[0]) in main. The compiler knows how big arr
is, so why the difference - esp. as it would be v.useful if sizeof(arr)
worked in someFunction as it does in main - so you could use sizeof(arr) in
the conditional bit of,say, a for loop in someFunction for example?

Because the 500 in
char * testFunction(char arr[500])

is completely meaningless. arr is a pointer to a char; the compiler
has no idea how many it points to. That's your job.
3. Why doesn't C allow testFunction to be declared char [] testFunction -

Because char[] and char * are not the same. IIRC, char [] is an array
of pointers of unspecified size.
seems to me that if it did you could get away with knowing less about
pointers,

Thus further burying the secrets of how to use them correctly...
 
M

Mark McIntyre

2. Why does sizeof(arr) not work consistently in C?

It does. Please read the documentation on it carefully, understand the
difrference between a pointer and an array, and understand what
happens to arrays when passed as parameters to functions.
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

No, its disastrous. You just overwrote memory that doesn't belong to
you.

Never lie to the compiler. Like your grandmother, it will find you out
and beat you with a willow twig.
 
E

Emmanuel Delahaye

jimbo a écrit :
Could someone comment on this code please.

First of all, you should learn to tune your compiler in a better way.

Compiling: main.c
main.c: In function `main_':
main.c:7: warning: initializer-string for array of chars is too long
main.c:10: error: implicit declaration of function `printf'
main.c:10: warning: nested extern declaration of `printf'
<internal>:0: warning: redundant redeclaration of 'printf'
main.c: In function `testFunction':
main.c:30: warning: nested extern declaration of `printf'
<internal>:0: warning: redundant redeclaration of 'printf'
main.c:26: warning: unused variable `n'
main.c:33:3: warning: no newline at end of file
Process terminated with status 1 (0 minutes, 0 seconds)
1 errors, 5 warnings
1. Are the comments in it correct?

/* -ed-
missing header for printf()
(a prototype in scope is mandatory for variadics functions)
*/
#include <stdio.h>

char * testFunction(char []);

int main(void)
{
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

/* -ed- I have this (gcc/mingw):

main.c:19: warning: initializer-string for array of chars is too long

sounds enough to me.

On another compiler (BC 3.1), I have a compile error.
*/

/* Ouput the sizeof the array. And the size of a pointer to it. */
printf("main() sizeof arr = %d\n", sizeof(arr));
printf("main() sizeof arr = %d\n", sizeof(&arr[0]));

/* Pass it on to the function where we'll do some other emaningless
things.*/
testFunction(arr);
return 0;
}

/* Can't declare testFunction as char [] testF...() - even though the
compiler knows that array's are passed by address.*/
/* -ed- What's wrong with

char * testF...()

which is exactly the reflect of the truth ?
*/

/* The size is ignored - and can't be checked anyway.*/
/* -ed-
True. This is because of the type you used (pointer to an element).
Try 'pointer to an array' and it will be different. (But hard to
maintain).
The pointer to element way is simple and dynamic.
Just add a nb_of_elements parameter.
*/
char * testFunction(char arr[500])
{
int n;
/* -ed- never used...

main.c:38: warning: unused variable `n'

*/

/* Same sizeof line of code that was in main() - note here that it
output the size of a pointer!*/
printf("sizeof arr = %d\n", sizeof(arr));
/* -ed-
Undefined behaviour. sizeof returns a size_t. You want

printf("sizeof arr = %zu\n", sizeof(arr));

or

printf("sizeof arr = %lu\n", (unsigned long) sizeof arr);

but keep in mind that 'arr' is just another pointer.
You will have the sizeof a a pointer, not to the pointed array.
An extra parameter is required for that
(all the difference between gets() and fgets()).

Note that the parens are not required with objects.

*/
return arr;
}
2. Why does sizeof(arr) not work consistently in C?

It does. Just don't mix arrays and pointers.
 
F

Flash Gordon

Emmanuel said:
Flash Gordon a écrit :
Or more likely, an address...

The last time I looked the null pointer was not an address, although I
will happily accept correction if someone can point out something in the
standard that says otherwise. So I think it more accurate to talk of
returning a pointer than an address.
 
K

Keith Thompson

jimbo said:
Could someone comment on this code please.

1. Are the comments in it correct?

2. Why does sizeof(arr) not work consistently in C? In someFunction()
sizeof(arr) means sizeof(&arr[0]) in main. The compiler knows how big arr
is, so why the difference - esp. as it would be v.useful if sizeof(arr)
worked in someFunction as it does in main - so you could use sizeof(arr) in
the conditional bit of,say, a for loop in someFunction for example?

3. Why doesn't C allow testFunction to be declared char [] testFunction -
seems to me that if it did you could get away with knowing less about
pointers, and it seems as though again that C is incosistent, i.e., you
don't have to declare testFunction's parameter as char *. Surely, the
compiler should know that char [] someFunction actually means char *
someFunction??

char * testFunction(char []);

int main(void)
{
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

What do you mean "should be ok"? To handle this, the compiler would
either have to make arr bigger than you asked, or ignore part of the
initializer; neither is a sensible thing to expect.

I'm not sure whether this is a constraint violation or undefined
behavior, but it's certainly a bad idea (as lying to the compiler
always is). Don't do that.

(If the initializer were too short, the remaining elements would be
initialized to zero.)

As for the rest of your questions, C's treatment of arrays and
pointers is actually (mostly) consistent, though it can be confusing.
Section 6 of the comp.lang.c FAQ has a lot of good information; you
can find it at <http://www.eskimo.com/~scs/C-faq/top.html>.

To summarize:

Arrays are arrays. Pointers are pointers. Arrays are not pointers.
Pointers are not arrays. Anyone who tells you otherwise is mistaken.

An expression of array type, in most contexts, is implicitly converted
to a pointer to the array's first element; this conversion does not
happen for the operand of a unary "&" or "sizeof" operator, or for a
string literal used to initialize an array. (Thus you can initialize
an array object with a string literal, but you can't *assign* a string
literal to an array object.)

As a special case, a parameter declaration such as
void func(SOME_TYPE *param);
can be written as
void func(SOME_TYPE param[]);
These are equivalent; the latter really declares a pointer, not an
array. This makes it slightly easier to ignore the distinction
between pointers and arrays. In my opinion, it was a mistake to have
this feature in the language. This equivalence applies only to
function parameters; in particular, it does not apply to function
return types. (It's been argued that the param[] form is useful to
document the intent that the argument should be an array, but the
compiler doesn't check this. If you want to document something that
the compiler can't check, you can use a comment.)

The indexing operator x[y], takes two operands, a pointer and an
integer (*not* an array and an integer). Typically, the pointer
operand is going to be an array name, which will be implicitly
converted to a pointer before the indexing operator sees its value.
x[y] is by definition equivalent to *(x+y). (Because addition is
commutative, x[y] can be written as [y]x; this odd little quirk is in
no way useful.)
 
S

Simon Biber

Christopher said:
jimbo said:
3. Why doesn't C allow testFunction to be declared char [] testFunction -


Because char[] and char * are not the same. IIRC, char [] is an array
of pointers of unspecified size.

You remember incorrectly. In the parameter list of a function, char[]
and char* are exactly the same. In any other declaration they are
different. char[] is never an array of pointers. It can represent an
array of char, of unspecified size. If an initialiser is provided, it
represents an array of char, of the size required to contain the
initialiser. For example,

$ cat foo.c

#include <stdio.h>

/*
The following line declares an array of char of unspecified size. It
is OK to use this array, but not to ask the compiler about its size
within this translation unit.
*/
extern char bar[];

void print_bar(void)
{
puts(bar);
}

$ cat bar.c

/*
The following line defines an array of char whose size is inferred
from the initialiser given, so it will be 13 chars long. It is OK
to both use this array and ask the compiler about its size within
this translation unit.
*/
char bar[] = "hello, world";

void print_bar(void);

int main(void)
{
print_bar();
return 0;
}

$ c99 -pedantic -Wall -W -O2 -c foo.c
$ c99 -pedantic -Wall -W -O2 -c bar.c
$ c99 foo.o bar.o -o foobar
$ ./foobar
hello, world
 
K

Keith Thompson

Emmanuel Delahaye said:
Flash Gordon a écrit :
Or more likely, an address...

Is this the old argument about the meanings of the terms "pointer" and
"address"?

It's reasonable, IMHO, to use the term "pointer" only to refer to an
object of pointer type, and the term "address" to refer to a *value*
of pointer type. Thus the value of a pointer object is an address. I
generally try to use the terms this way myself.

But the standard doesn't make this distinction, at least not
consistently. For example, the malloc() function "returns either a
null pointer or a pointer to the allocated space".

I think we have to accept that referring to a pointer value, such as
"returning a pointer", is acceptable.

If that wasn't your point, wha was?
 
S

Simon Biber

Mark said:
2. Why does sizeof(arr) not work consistently in C?


It does. Please read the documentation on it carefully, understand the
difrference between a pointer and an array, and understand what
happens to arrays when passed as parameters to functions.

/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";


No, its disastrous. You just overwrote memory that doesn't belong to
you.

Any compiler worth its salt will diagnose that error at compile time,
and so you will fix the problem, and never get to the stage of actually
overwriting memory.

In fact, it is a constraint, and as such must be diagnosed by a
standard-conforming C compiler:

6.7.8 Initialization
...
Constraints
2 No initializer shall attempt to provide a value for an object not
contained within the entity being initialized.
 
B

Barry Schwarz

2. Why does sizeof(arr) not work consistently in C?

It does. Please read the documentation on it carefully, understand the
difrference between a pointer and an array, and understand what
happens to arrays when passed as parameters to functions.
/* Lie to the compiler. Should be ok though as the compiler knows how
big the array really is.*/
char arr[7] = "0123456789";

No, its disastrous. You just overwrote memory that doesn't belong to
you.

Isn't this simply a constraint violation (6.7.8-2) that requires a
diagnostic? Do any existing compilers actually initialize more than
the 7 bytes defined?


<<Remove the del for email>>
 
C

Christopher Benson-Manica

Simon Biber said:
You remember incorrectly. In the parameter list of a function, char[]
and char* are exactly the same. In any other declaration they are
different. char[] is never an array of pointers. It can represent an
array of char, of unspecified size.

That is what I meant to say; the fact that I did not is disturbing. I
appreciate the correction.
 
B

buda

Keith Thompson said:
The indexing operator x[y], takes two operands, a pointer and an
integer (*not* an array and an integer). Typically, the pointer
operand is going to be an array name, which will be implicitly
converted to a pointer before the indexing operator sees its value.
x[y] is by definition equivalent to *(x+y). (Because addition is
commutative, x[y] can be written as [y]x; this odd little quirk is in
no way useful.) ^^^^

ITYM "x[y] can be written as y[x]". For example, "123"[1] is equivalent to
1["123"], but [1]"123" is a syntax error.
 
E

Emmanuel Delahaye

Keith Thompson a écrit :
Is this the old argument about the meanings of the terms "pointer" and
"address"?

Yes. Based on the fact that a pointer is an variable whose value is an
address, an address itself is a pointer constant. It's also the value of
a pointer. (like 123 is an integer constant and also the value of
variable of type char or int etc.)
It's reasonable, IMHO, to use the term "pointer" only to refer to an
object of pointer type, and the term "address" to refer to a *value*
of pointer type.

I'm glad to read that.
Thus the value of a pointer object is an address. I
generally try to use the terms this way myself.

But the standard doesn't make this distinction, at least not
consistently. For example, the malloc() function "returns either a
null pointer or a pointer to the allocated space".

Too bad and confusing. I would have written it like this:

<<the malloc() function "returns either a null pointer constant or the
address of the allocated space">>

Of course, it is useful to store this address into a pointer. Once
stored, the pointer points to the allocated block.

Simple wording, simple meaning, no trick... I understand better why
people have hard time with pointers. Seems obvious that the semantic
around'em isn't clear and consistent enough.
I think we have to accept that referring to a pointer value, such as
"returning a pointer", is acceptable.

Unfortunately, yes.
 
E

Emmanuel Delahaye

Flash Gordon a écrit :
The last time I looked the null pointer was not an address,

There is no 'null pointer'. There is a 'null pointer constant' also
known as NULL.

Ok, I should have written :

although I
will happily accept correction if someone can point out something in the
standard that says otherwise. So I think it more accurate to talk of
returning a pointer than an address.

See Keith's response and my response to him.
 
P

pemo

Flash Gordon said:
jimbo wrote:
and it seems as though again that C is incosistent, i.e., you
don't have to declare testFunction's parameter as char *. Surely, the
compiler should know that char [] someFunction actually means char *
someFunction??

If both were valid they would mean different things. One would mean
returning an array, which C does not allow, whilst the other does mean
returning a pointer to char.

"If both were valid they would mean different things"

Hmmmm

Suerly, there is an inconsistency here with char ?[]

If

char * someFunction(char arr[])

Can also be written [and has the same meaning as]

char * someFunction(char * arr)

Then we can interpret char arr[] as a parameter type as *NOT* meaning that
an array is passed. E.g., both of these *are* valid, and they both mean
*the same thing*. So "If both were valid they would mean different things"
is not necessarily a good argument against not allowing this as a return
type IMHO.

Why not interpret - consistently with this in a
function-definition/declaration sense - char [] someFun.... as *NOT* meaning
that an array is returned then?

Also, as using char [] as a return type will cause a compiler error, in the
future, its meaning could be 'aligned' with its use when used as a parameter
without breaking any 'old' code. IMHO, this would be a useful semantic
alignment to make.
 
P

pemo

Simon Biber said:
Christopher Benson-Manica wrote:
Because char[] and char * are not the same. IIRC, char [] is an array
of pointers of unspecified size.

You remember incorrectly. In the parameter list of a function, char[] and
char* are exactly the same. In any other declaration they are different.

I think this is the OP's point - please see my other post re its use as a
return type.
 
F

Flash Gordon

Emmanuel said:
Keith Thompson a écrit :

Yes. Based on the fact that a pointer is an variable whose value is an
address, an address itself is a pointer constant. It's also the value of
a pointer. (like 123 is an integer constant and also the value of
variable of type char or int etc.)

The problems I see with the term address are:
1) If you talk about returning an address you either imply that a null
pointer constant is an address leading to confusion about what you
can do with it, or continually say "address or null pointer" (or
something similar.
2) You are likely to confuse people about what they cad do. IMHO that
since address is a term used when talking about the hardware where no
type is involved (it is just memory), where as pointers are not.

After all, in summary, C pointers are slightly more abstract than
machine addresses.

<<the malloc() function "returns either a null pointer constant or the
address of the allocated space">>

Of course, it is useful to store this address into a pointer. Once
stored, the pointer points to the allocated block.

I think it would be simpler if pointer or pointer value was used
throughout, see above. Just as I would refer to an int being returned by
a function.
Simple wording, simple meaning, no trick... I understand better why
people have hard time with pointers. Seems obvious that the semantic
around'em isn't clear and consistent enough.

Agreed. It would be better if consisten terminology is used.
Unfortunately, yes.

I think it would be better if the term "address" was not used, expect
when talking about how pointers are implemented and possibly talking
about converting between pointer types. However, I recognise this is
very much my personal opinion, and I have no authority to call on, so
I'm certainly not going to complain about people talking about
addresses. I certainly see no point to a long discussion on this subject.
 
F

Flash Gordon

Emmanuel said:
Flash Gordon a écrit :

There is no 'null pointer'.

The C standard refers to "a null pointer" in serveral places. Such as,
in n1124.pdf, section 5.1.2.2.1 Program startup, "argv[argc] shall be a
null pointer.", a good one is section 6.3.2.3 Pointers where it says:
| 3 An integer constant expression with the value 0, or such an
| expression cast to type void *, is called a null pointer
| constant.55) If a null pointer constant is converted to a pointer
| type, the resulting pointer, called a null pointer, is guaranteed to
^^^^^^^^^^^^^^^^^^^^^
| compare unequal to a pointer to any object or function.

I think it is fair to say that if the standard says that is a null
pointer constant is converted to a pointer type the resulting pointer is
called a null pointer that null pointers definitely do exist according
to the standard.

There are also many other references to 'null pointer' as opposed to
'null pointer constant' in the standard, and I can't believe that all of
them where added after the C89 standard.
> There is a 'null pointer constant' also
known as NULL.

No, NULL is a macro that expands to a null pointer constant, and the
last time I checked 0 was not known as NULL, although it is most
definitely a null pointer constant.
Ok, I should have written :



See Keith's response and my response to him.

I don't see that those responses prove me wrong. See my reply to them.
In addition, in n1124, section 7.20.3.3 The malloc function it says:
| 3 The malloc function returns either a null pointer or a pointer to
| the allocated space.

If the *standard* talks about a standard library function returning a
pointer then as far as I can see it *must* be valid to talk about
functions returning pointers. Or are you saying that if I write a function:
#include <stdlib.h>
void *my_malloc(size_t s)
{
return malloc(s);
}
That is somehow mysteriously stops being a pointer after malloc has
returned it just because it is my function returning it?
 

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

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top