6

This is more of a conceptual question at this point rather than a practical one but it is really bothering me.

Let us say I have a c program called "test.c" and I want to find the number of spaces in array there are for a word the user types in as an argument. For example "./test.c test_run" should print 9 because there are 8 characters and then one for the null terminating character. When I try to use sizeof on argv though I am having some trouble.

int main(int argc, char *argv[]) { char buf10[10]; printf("The size of buf10 is: %i.\n", sizeof(buf10)); return 0; } 

Prints the result: "The size of buf10 is: 10.". This makes sense because I chose a char array. In C, the size of a char is 1 byte. If I chose int, this number would be 4.

Now my question is why can't I do this with argv?

int main(int argc, char *argv[]) { printf("argv[1] has the value: %s\n", argv[1]); printf("strlen of argv[1] is: %i\n", strlen(argv[1])); printf("sizeof of argv[1] is: %i\n", sizeof(argv[1])); return 0; } 

Ran with "./test Hello_SO" gives the output:

argv[1] has the value: Hello_SO strlen of argv[1] is: 8 sizeof of argv[1] is: 4 

The string length makes sense because it should be 9 but minus the "\0" makes 8.

However I do not understand why sizeof is returning 4 (the size of the pointer). I understand that *argv[] can be thought of as **argv. But I accounted for this already. In my first example i print "buf" but here i print "argv[1]". I know I could easily get the answer by using strlen but as I said earlier this is just conceptual at this point.

9
  • Sounds like you have perhaps answered your own question. Commented Sep 30, 2014 at 1:15
  • argv[1] has type char *, so sizeof argv[1] means sizeof(char *). That's what sizeof does. Commented Sep 30, 2014 at 1:18
  • But why does buf10 print 10 and argv[1] not print 9. buf10 is also a pointer is it not? Commented Sep 30, 2014 at 1:20
  • 2
    buf10 is an array type, not a pointer. Commented Sep 30, 2014 at 1:38
  • 1
    @StevenK Both are available at compile-time; the question is whether the compiler will apply the optimisation in that case. You should use %zu to print size_t values... Okay, I misunderstood your question initially. Perhaps a more illuminating example: char *fubar = "hello world"; What kind of value do you expect sizeof NULL to produce, compared to sizeof fubar? Should sizeof attempt to follow the pointer to find out the size of that which is pointed at? If so, then the first example is surely invalid, right? Commented Jan 16, 2016 at 17:31

2 Answers 2

4

Pointers and arrays are not the same thing, though they are quite similar in many situations. sizeof is a key difference.

int arr[10]; assert(sizeof arr == (sizeof(int) * 10)); int *ip; assert(sizeof ip == sizeof(int*)); 

The type of arr above is int[10]. Another way to see the difference between array types and pointers is by trying to assign to them.

int i; ip = &i; // sure, fine arr = &i; // fails, can't assign to an int[10] 

arrays cannot be assigned to.

What is most confusing is that when you have an array as a function parameter, it actually is the same has having a pointer.

int f(int arr[10]) { int x; arr = &x; // fine, because arr is actually an int* assert(sizeof arr == sizeof(int*)); } 

To address your question of why you can't use sizeof argv[1] and get the size of the string (plus the 1 for the \0), it's because it's a ragged array. In this case the first dimension is of unknown size, as well as the second. sizeof behaves like a compile time operation in this case, and the length of the string is not known until run time.

Consider the following program:

#include <stdio.h> int main(int argc, char *argv[]) { printf("%zu\n", sizeof argv[1]); } 

The assembly generated for this is:

.LC0: .string "%zu\n" .text .globl main .type main, @function main: .LFB3: .cfi_startproc subq $8, %rsp .cfi_def_cfa_offset 16 movl $8, %esi # this 8 is the result of sizeof movl $.LC0, %edi # the format string movl $0, %eax call printf # calling printf movl $0, %eax addq $8, %rsp .cfi_def_cfa_offset 8 ret .cfi_endproc 

as you can see, the result of sizeof argv[1] is done at compile time, nothing above is computing the length of the string. I'm on 64-bit so my pointers are 8 bytes.

Sign up to request clarification or add additional context in comments.

6 Comments

The confusion is really caused by the fact that you CANNOT HAVE an array as a function parameter -- if you declare a function parameter as an array, the compiler silently turns it into a pointer for you, "helpfully" concealing any misunderstanding and leading to errors like these.
@ChrisDodd yes, but don't forget about multidimensional arrays which have different rules.
No such thing as multidimensional arrays in C -- only arrays of arrays, which turn into pointers when used as arguments, just like any other array. Then there's also the confusion between arrays of arrays and arrays of pointers, which are completely different despite the fact they can be accessed with the same syntax.
@ChrisDodd whether or not to call them multidimensional arrays, I'm just pointing out that int f(int a[][5]) { printf("%zu\n", sizeof a[0]); } prints sizeof(int) * 5 not sizeof(int *)
@StevenK I think you mean int *const
|
1

The buf10 variable is known at compile-time to be a (contiguous) array of ten characters. The other pointers are dynamically allocated, and are pointers to a character. This is why you get the size of the character array vs the sizeof(char *).

2 Comments

So is there a difference between char buf10[10] = "Hello" and char buf10[] = "Hello" then?
the latter will compute the length of the array based on how much space is needed to store "Hello". so the size of will be 6. It's still an array though. If you did const char *s = "Hello" then sizeof s would be sizeof(char *)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.