5
#include "stdio.h"

#define COUNT(a) (sizeof(a) / sizeof(*(a)))

void test(int b[]) {
  printf("2, count:%d\n", COUNT(b));
}

int main(void) {
  int a[] = { 1,2,3 };

  printf("1, count:%d\n", COUNT(a));
  test(a);

  return 0;
}

The result is obvious:

1, count:3
2, count:1

My questions:

  1. Where is the length(count/size) info stored when "a" is declared?
  2. Why is the length(count/size) info lost when "a" is passed to the test() function?
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Lion
  • 965
  • 10
  • 21
  • 1
    The C standard says '`#include `' and you should practice being consistent with the standard - unless you've really got a good enough reason not to do so (but, if you knew enough to be sure of your footing on the notation, you wouldn't need to ask this question). – Jonathan Leffler Dec 24 '10 at 21:30

6 Answers6

8

There's no such thing as "array pointer" in C language.

The size is not stored anywhere. a is not a pointer, a is an object of type int[3], which is a fact well known to the compiler at compile time. So, when you ask the compiler to calculate sizeof(a) / sizeof(*a) at compile time the compiler knows that the answer is 3.

When you pass your a to the function you are intentionally asking the compiler to convert array type to pointer type (since you declared the function parameter as a pointer). For pointers your sizeof expression produces a completely different result.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • thank you! i think i'm clear now. – Lion Dec 24 '10 at 07:41
  • +1 for `a` is an object of type `int[3]` although I don't necessarily agree with the statement that he declared the function parameter as a pointer since he used `int b[]` and not `int *b`. It's just that the standard dictates that arrays passed as parameters decay to a pointer to the first element. – SiegeX Dec 24 '10 at 09:00
  • 2
    @SiegeX: Standard explicitly states that `int b[]` in the parameter declaration is equivalent to `int *b`. This is not an instance of the "array type decay". Arguments can "decay", but parameter declaration are covered by a different "process" described by a separate section of the standard. – AnT stands with Russia Dec 24 '10 at 14:55
  • §6.7.5.3/6 and /7 of C99 (ISO/IEC 9899:1999) say: "6 A parameter type list specifies the types of, and may declare identifiers for, the parameters of the function. 7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to type’’,". – Jonathan Leffler Dec 24 '10 at 16:45
  • @Jonathan I read that as backing up my statement, the user declared it as 'array of type' but it will be adjusted behind the scenes to 'pointer to type'. Although it uses the word 'adjusted' over 'decay', seems to me they are synonyms. – SiegeX Dec 24 '10 at 17:49
  • Yes - it was meant to be documentary confirmation that the standard says what you said it says. – Jonathan Leffler Dec 24 '10 at 21:27
  • 1
    Well, again, the "array type decay" is not a precisely defined term. Again, what happens to parameter declarations of array type and to actual arrays has lots of similarities, of course. Yet, semantically these two processes are significantly different. Semantically, actual array object decaying to pointer is one thing, and array parameter declaration getting replaced with pointer declaration is totally another thing. You can call both "array type decay", all right. But in this context, where the distinction matters, mixing the two together would be a mistake. – AnT stands with Russia Dec 24 '10 at 22:14
5
  1. Where is the length(count/size) info stored when "a" is declared?

It's not stored anywhere. The sizeof operator (used in the COUNT() macro) returns the size of the entire array when it's given a true array as the operand (as it is in the first printf())

  1. Why is the length(count/size) info lost when "a" is passed to the test() function?

Unfortunately, in C, array parameters to functions are a fiction. Arrays don't get passed to functions; the parameter is treated as a pointer, and the array argument passed in the function call gets 'decayed' into a simple pointer. The sizeof operator returns the size of the pointer, which has no correlation to the size of the array that was used as an argument.

As a side note, in C++ you can have a function parameter be a reference to an array, and in that case the full array type is made available to the function (i.e., the argument doesn't decay into a pointer and sizeof will return the size of the full array). However, in that case the argument must match the array type exactly (including the number of elements), which makes the technique mostly useful only with templates.

For example, the following C++ program will do what you expect:

#include "stdio.h"

#define COUNT(a) (sizeof(a) / sizeof(*(a)))

template <int T>
void test(int (&b)[T]) {
  printf("2, count:%d\n", COUNT(b));
}

int main(int argc, char *argv[]) {
  int a[] = { 1,2,3 };

  printf("1, count:%d\n", COUNT(a));
  test(a);

  return 0;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • 1
    thank you. you answer makes it more clear to me. so the last question: what's the difference between the two pointers: &(a[0]) and a ? – Lion Dec 24 '10 at 07:35
  • 1
    Strictly speaking, `a` is not a pointer - it's an array. However, in nearly all expressions (one exception is when it's the argument to `sizeof`), it 'decays' into a pointer that is exactly the same value and type as `&(a[0]])`. – Michael Burr Dec 24 '10 at 07:43
  • thanks again for your reply! i'm clear now. – Lion Dec 24 '10 at 08:08
  • 1
    Your answer to (1) is partially incorrect. If the array is variable-length, then the length is stored somewhere and retrievable with `sizeof`, but where it's stored is an implementation detail and the closest thing anyone could give to an answer is "in `sizeof array`". – R.. GitHub STOP HELPING ICE Dec 24 '10 at 13:19
  • @R.. - you're right about VLAs. I often forget about them since I don't use them except experimentally (they're generally not supported on the platforms I deal with). I sometimes wonder how much real world use they get? – Michael Burr Dec 24 '10 at 23:30
  • @Michael: Hopefully not much. As I've discussed on many other questions, it's almost impossible to use VLA's in a way that's both safe and has any practical advantages over a fixed-size automatic array. I had to work really hard to invent a class of recursive algorithms where they're definitely useful. – R.. GitHub STOP HELPING ICE Dec 28 '10 at 03:34
1
  1. Nowhere.
  2. Because it wasn't stored in the first place.

When you refer to the array in main(), the actual array declaration definition is visible, so sizeof(a) gives the size of the array in bytes.

When you refer to the array in the function, the parameter is effectively 'void test(int *b), and the size of the pointer divided by the size of the thing it points at happens to be 1 on a 32-bit platform, whereas it would be 2 on a 64-bit platform with LP64 architecture (or, indeed, on an LLP64 platform like Windows-64) because pointers are 8 bytes and int is 4 bytes.

There isn't a universal way to determine the size of an array passed into a function; you have to pass it explicitly and manually.


From the comment:

I still have two questions:

  1. What do you mean by "..the actual declaration is visible.."? [T]he compiler (or OS) could get the length info through sizeof(a) function?
  2. Why the pointer &(a[0]) doesn't contain the length info as the pointer "a"?
  1. I think you learned Java before you learned C, or some other more modern language. Ultimately, it comes down to "because that is the way C is defined". The OS is not involved; this is a purely compiler issue.

    • sizeof() is an operator, not a function. Unless you are dealing with a VLA (variable length array), it is evaluated at compile time and is a constant value.

    Inside main(), the array definition (I misspoke when I said 'declaration') is there, and when the sizeof() operator is applied to the name of an actual array - as opposed to an array parameter to a function - then the size returned is the size of the array in bytes.

  2. Because this is C and not Algol, Pascal, Java, C#, ...

    C does not store the size of the array - period. That is a fact of life. And, when an array is passed to a function, the size information is not passed to the function; the array 'decays' to a pointer to the zeroth element of the array - and only that pointer is passed.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • thank you. i still have two questions: 1, what do you mean by "..the actual declaration is visible.."? why the compiler(or OS) could get the length info through sizeof(a) function? 2, why the pointer &(a[0]) doesn't contain the length info as the pointer "a"? – Lion Dec 24 '10 at 07:30
1
1. Where is the length(count/size) info stored when "a" is declared?

It isn't stored. The compiler knows what a is and therefore knows it's size. So the compiler can replace sizeof() with the actual size.

2. Why is the length(count/size) info lost when "a" is passed to the test() function?

In this case, b is declared as a pointer (even though it may point to a). Given a pointer, the compiler does not know the size of the data pointed to.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
0
  1. Where is the length(count/size) info stored when "a" is declared?

Nowhere. The question doesn't make sense BTW.

  1. Why is the length(count/size) info lost when "a" is passed to the test() function?

Array decays into pointer(to the first element) when passed to a function. So the answer is 'nowhere' and similar to the previous question this one again doesn't make any sense.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
0

Array pointer does not store the size. However, the[] type is not actually a pointer. It's a different type. When you say int a[] = {1,2,3}; you define array of 3 elements, and since it is defined so, sizeof(a) gives you the size of the whole array.

When however you declare parameter as int a[], it's pretty much the same as int *a, and sizeof(a) would be the size of the pointer (which coincidentally may be the same as the size of int, but not always).

In C, there's no way to store the size in pointer type, so if you need the size, you'd have to pass it as additional argument or use struct.

StasM
  • 10,593
  • 6
  • 56
  • 103