sizeof()'s strange behviour

P

Philip Potter

arnuld said:
sizeof() operator gives 2 different types of size outputs :\ but I do not
understand why:

#include <stdio.h>
#include <stdlib.h>


int my_size( char [] );


int main()
{
char s[] = "Saurabh Nirkhey";

printf("sizeof(%s): %d\n", s, sizeof(s));
printf("sizeof(%s): %d\n", s, my_size(s));


return 0;
}

int my_size( char s[] )
{
return sizeof(s);
}

In C, arrays cannot be used as function parameters. While it looks like
my_size() takes a char [], C rewrites the declaration so that it
actually takes a char *. The value passed to my_size() is a pointer to
the first element of s (if it helps, you can think of it as &s[0]). The
s within my_size is therefore a char *, and sizeof(s) tells you the size
of a char *.

Usually strlen() is the correct tool when dealing with strings.

See also FAQ question 6.4 (the clc FAQ is at http://c-faq.com/), and the
whole of section 6 is probably useful.

pgp@bullfinch:~/tmp$ cat str.c
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[10] = "String";
char str2[100] = "String";
printf("str1 and str2 are %s\n",
strcmp(str1,str2) == 0 ? "equal" : "not equal");
printf("strlen(str1) == %d, strlen(str2) == %d\n",
strlen(str1),strlen(str2));
printf("sizeof str1 == %d, sizeof str2 == %d\n",
sizeof str1, sizeof str2);
return 0;
}
pgp@bullfinch:~/tmp$ gcc -ansi -pedantic -ostr str.c
pgp@bullfinch:~/tmp$ ./str
str1 and str2 are equal
strlen(str1) == 6, strlen(str2) == 6
sizeof str1 == 10, sizeof str2 == 100
pgp@bullfinch:~/tmp$

The above shows that sizeof and strlen are measuring different things.
sizeof tells you the size of a type (in this case two array types,
char[10] and char[100]), while strlen() tells you the length of a string
(which may not fill the whole array).
 
A

arnuld

sizeof() operator gives 2 different types of size outputs :\ but I do not
understand why:


#include <stdio.h>
#include <stdlib.h>


int my_size( char [] );


int main()
{
char s[] = "Saurabh Nirkhey";

printf("sizeof(%s): %d\n", s, sizeof(s));
printf("sizeof(%s): %d\n", s, my_size(s));


return 0;
}



int my_size( char s[] )
{
return sizeof(s);
}


============ OUTPUT =============
/home/arnuld/programs/C $ gcc -ansi -pedantic -Wall -Wextra 5-4.c
/home/arnuld/programs/C $ ./a.out
sizeof(Saurabh Nirkhey): 16
sizeof(Saurabh Nirkhey): 4
/home/arnuld/programs/C $


--http://lispmachine.wordpress.com/

Please remove capital 'V's when you reply to me via e-mail.
 
K

Keith Thompson

Richard Heathfield said:
arnuld said: [...]
printf("sizeof(%s): %d\n", s, sizeof(s));

...so we'd expect this to print 16 in place of the second % format
specifier. Note that your printf is misleading. It will print:

sizeof(Saurabh Nirkhey): 16

but in fact it's sizeof s that is 16.
[...]

Furthermore, "%d" causes printf to expect an int argument, but
sizeof(s) is of type size_t. It's likely to happen to work on systems
where int and size_t are the same size, but the right way is (with a
couple of other tweaks):

printf("sizeof s: %d\n", (int)sizeof s);
 
P

Philip Potter

Keith said:
Richard Heathfield said:
arnuld said: [...]
printf("sizeof(%s): %d\n", s, sizeof(s));
...so we'd expect this to print 16 in place of the second % format
specifier. Note that your printf is misleading. It will print:

sizeof(Saurabh Nirkhey): 16

but in fact it's sizeof s that is 16.
[...]

Furthermore, "%d" causes printf to expect an int argument, but
sizeof(s) is of type size_t. It's likely to happen to work on systems
where int and size_t are the same size, but the right way is (with a
couple of other tweaks):

printf("sizeof s: %d\n", (int)sizeof s);
Richard mentioned this already in his post.

I'd add that C99 provides the 'z' format modifier for size_t values:

printf("sizeof s: %zd\n", sizeof s);

....although if your code isn't C99 for other reasons, this is hardly a
great reason to break C90 compatibility.
 
K

Keith Thompson

Philip Potter said:
Keith said:
Richard Heathfield said:
arnuld said: [...]
printf("sizeof(%s): %d\n", s, sizeof(s));
...so we'd expect this to print 16 in place of the second % format
specifier. Note that your printf is misleading. It will print:

sizeof(Saurabh Nirkhey): 16

but in fact it's sizeof s that is 16.
[...]

Furthermore, "%d" causes printf to expect an int argument, but
sizeof(s) is of type size_t. It's likely to happen to work on systems
where int and size_t are the same size, but the right way is (with a
couple of other tweaks):

printf("sizeof s: %d\n", (int)sizeof s);
Richard mentioned this already in his post.

Did he? I expected him to do so, and I was surprised when I didn't
see it, and surprised again when I didn't see it when I re-read his
article just now. He did mention that size_t yields a size_t rather
than an int, but in the context of returning the result from the OP's
my_size() function, not in the context of passing the result to
printf.

[...]
 
A

arnuld

Anyway, bottom line is: what you've discovered is that you can't pass
arrays to functions. You can fake it, but you can't actually pass the
array itself. If you try to take an array's value (e.g. by passing it to a
function or adding it to an integer value), what you actually get is a
pointer to the array's first element.
.... {SNIP}...
So evaluating the name of an array gives a pointer to the first element,
QED.


okay, I have written this. So now I know about both sizeof() and that
arrays can not be passed to functions :

/* A program to understand the output of sizeof operator
*
*/



#include <stdio.h>
#include <stdlib.h>


int main()
{
int arr_char, arr_int, arr_LD;
char ac[] = "abc";
int ai[] = { 1, 2, 3};
long double ald[] = { 1.3, 78659.90098, 0.0001 };

/* casting to int because sizeof yields a size_t value */
arr_char = (int) sizeof( ac );
arr_int = (int) sizeof( ai );
arr_LD = (int) sizeof( ald );

printf("Size of different types of Arrays in BYTES: \n");
printf("\n%d\n", arr_char);
printf("%d\n", arr_int);
printf("%d\n", arr_LD);

arr_char = ( (int) sizeof(ac) / sizeof(char) ) - 1;
arr_int = ( (int) sizeof(ai) / sizeof(int) );
arr_LD = ( (int) sizeof(ald) / sizeof(long double) );
printf("\nSize of Arrays themselves, number of elements they contain: \n");
printf("\n%d\n", arr_char);
printf("%d\n", arr_int);
printf("%d\n", arr_LD);


return EXIT_SUCCESS;
}

========= OUTPUT ==============
/home/arnuld/programs/C $ gcc -ansi -pedantic -Wall -Wextra test.c
/home/arnuld/programs/C $ ./a.out
Size of different types of Arrays in BYTES:

4
12
36

Size of Arrays themselves, number of elements they contain:

3
3
3
/home/arnuld/programs/C $




-- http://lispmachine.wordpress.com/

Please remove capital 'V's when you reply to me via e-mail.
 
K

Keith Thompson

arnuld said:
okay, I have written this. So now I know about both sizeof() and that
arrays can not be passed to functions :

/* A program to understand the output of sizeof operator
*
*/

Overall, it's not a bad demonstration, but I have few comments.
#include <stdio.h>
#include <stdlib.h>


int main()

Ok, but "int main(void)" is preferred.
{
int arr_char, arr_int, arr_LD;
char ac[] = "abc";
int ai[] = { 1, 2, 3};
long double ald[] = { 1.3, 78659.90098, 0.0001 };

/* casting to int because sizeof yields a size_t value */
arr_char = (int) sizeof( ac );
arr_int = (int) sizeof( ai );
arr_LD = (int) sizeof( ald );

The casts are unnecessary. Both size_t and int are integral types;
one will be implicitly converted to the other by the assignment.

The parentheses on the sizeof operators are also unnecessary; they're
needed only when the argument is a type name, or when you need them to
specify grouping. Thus:

arr_char = sizeof ac;
arr_int = sizeof ai;
arr_LD = sizeof ald;

Better yet, since these three variables hold the result of sizeof,
declare them as size_t (or maybe not; see below).
printf("Size of different types of Arrays in BYTES: \n");
printf("\n%d\n", arr_char);
printf("%d\n", arr_int);
printf("%d\n", arr_LD);

Good. Note that if you followed my advice above and declared these as
size_t, you'd need to cast them to int for printf. It's usually best
to declare something of the appropriate type for what it needs to
hold, but in this case using int does simplify the code. There are
always tradeoffs.
arr_char = ( (int) sizeof(ac) / sizeof(char) ) - 1;
arr_int = ( (int) sizeof(ai) / sizeof(int) );
arr_LD = ( (int) sizeof(ald) / sizeof(long double) );

More unnecessary casts and excessive parentheses. And the "- 1" for
arr_char presumably is intended to allow for the trailing '\0' on the
string -- but that '\0' is just as much part of the array as the 'a',
'b', and 'c' are. Your array ac is 4 elements long, not 3.

Note that sizeof(char) is 1 by definition.

And here's a good idiom for computing the length of an array:

arr_char = sizeof ac / sizeof ac[0];
arr_int = sizeof ai / sizeof ai[0];
arr_LD = sizeof ald / sizeof ald[0];

Of course, when using this idiom you have to make sure that the name
(ac, ai, or ald) is actually the name of an array object, not of, say,
a function parameter that's really a pointer.
printf("\nSize of Arrays themselves, number of elements they contain: \n");
printf("\n%d\n", arr_char);
printf("%d\n", arr_int);
printf("%d\n", arr_LD);


return EXIT_SUCCESS;
}

Good. (Note that "return 0;" is equally valid.)

[snip]
 

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,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top