3

Is this how you guys get size of an array in ANSI-C99? Seems kind of, um clunky coming from higher language.

int tests[7];
for (int i=0; i<sizeof(tests)/sizeof(int); i++) {
    tests[i] = rand();
}

Also this Segmentation faults.

int r = 10000000;
printf ("r: %i\n", r);
int tests[r];

run it:

r: 10000000
Segmentation fault

10000000 seg faults, but 1000000 works.

How do I get more info out of this? What should I be checking and how would I debug something like this? Is there a limit on C arrays? What's a segmentation fault?

user697111
  • 2,232
  • 8
  • 29
  • 40

6 Answers6

3

Getting size of an array in C is easy. This will give you the size of array in bytes.

sizeof(x)

But I guess what you require is number of elements, in that case it would be:

sizeof(x) / sizeof(x[0])

You can write a simple macro for this:

#define NumElements(x)  (sizeof(x) / sizeof(x[0]))

For example:

int a[10];
int size_a = sizeof(a); /* size in bytes */
int numElm = NumElements(a); /* number of elements, here 10 */
BiGYaN
  • 6,974
  • 5
  • 30
  • 43
  • Here, "byte" should be read as "char", which is not necessarily 8 bits, it could be larger. – unwind Apr 19 '11 at 09:12
  • @unwind, AFAIK, sizeof gives us the size in bytes. Could you please elaborate when this is not the case? – BiGYaN Apr 19 '11 at 10:52
  • @unwind: The C99 standard says the returned value is the size in bytes. (section 6.5.3.4). However, it also says various things that make `char` and "byte" more or less the same thing. – JeremyP Apr 19 '11 at 12:45
  • @JeremyP - that isn't necessarily informative. The original meaning of Byte (around 100 years ago, when it was first coined) was basically the space needed for a single character. The space needed for a single character (probably on a punched card for a tabulator), however, probably wasn't 8 bits at the time. The modern (at least 30 years) common-usage standard 8-bits definition of a byte isn't universally accepted or "official", so unless the C standard specifically says how many bits are in a byte (or a char)... –  Apr 19 '11 at 17:57
  • @Steve314: The original meaning of byte is irrelevant. In C99, sizeof is explicitly said to return the size in bytes. It also explicitly says sizeof(char) is 1. It also explicitly says that within the scope of the standard a byte and a character are the same thing (also defining terms like wide character and multibyte character to account for things like UTF-16 and UTF-8). Nowhere does C99 say a byte has 8 bits. – JeremyP Apr 20 '11 at 07:08
  • @JeremyP - unwind raised the issue of numbers of bits. You say that standard makes char and byte more or less the same thing. I'm just saying that *that* isn't very informative - if you don't know the size of a char, then saying that a char and a byte are basically the same thing doesn't tell you the size of a byte. On "nowhere does C99 say a byte has 8 bits" I didn't know that for sure, but suspecting it is *why* I wrote my comment. In the answer, though, yes - the meaning of byte is irrelevant since the sizeof is in bytes by definition, and doesn't vary depending on what "byte" means. –  Apr 21 '11 at 21:36
2

Why calculate the size?

Define a constant containing the size and use that when declaring the array. Reference the constant whenever you want the size of the array.

As a primarily C++ programmer, I'll say that historically the constant was often defined as an enum value or a #define. In C, that may be current rather than historic, though - I don't know how current C handles "const".

If you really want to calculate the size, define a macro to do it. There may even be a standard one.

The reason for the segfault is most likely because the array you're trying to declare is about 40 megabytes worth, and is declared as a local variable. Most operating systems limit the size of the stack. Keep your array on the heap or in global memory, and 40 megabytes for one variable will probably be OK for most systems, though some embedded systems may still cry foul. In a language like Java, all objects are on the heap, and only references are kept on the stack. This is a simple and flexible system, but often much less efficient than storing data on the stack (heap allocation overheads, avoidable heap fragmentation, indirect access overheads...).

  • Thanks. How do I tell my stack limit and how could I debug this to determine if that is the case or not? – user697111 Apr 19 '11 at 04:51
  • @user697111 - to be honest I haven't a clue. I know this size limit exists, is smaller than many people think, and varies from platform to platform, but I never worried about it more than that. I haven't worried about multi-kilobyte locals for years, but even those aren't typical - large objects tend to live on the heap irrespective because they tend to be long-lived, and to outlive the function that created them. Also, even if I knew the exact figure for my machine, I couldn't use that knowledge - someone else's machine will have a smaller limit. –  Apr 19 '11 at 05:02
  • 1
    May be this helps: http://stackoverflow.com/questions/53827/checking-available-stack-size-in-c – Dakshinamurthy Karra Apr 19 '11 at 05:10
  • @KDM - good link - I particularly like Steve Jessops "conspiracy of silence" comment to the accepted answer. –  Apr 19 '11 at 05:17
  • A point worth adding - this stack size issue is a reason to prefer iterative algorithms to recursive, unless you can be confident that your compiler will convert the recursion to iteration. Guarantees along those lines are common in functional languages, but there's no guarantee in C. In practice, a compiler like GCC can optimise to iterative in more cases than just tail recursion, but (particularly in C++ rather than C) the possibility of thinking something will optimise when it won't is an issue. The "optimisation" often isn't an optimisation - it's a correctness issue. –  Apr 19 '11 at 05:31
1

Traditionally, an array has a static size. So we can do

#define LEN 10
int arr[LEN];

but not

int len;
scanf("%d", &len);
int arr[len]; // bad!

Since we know the size of an array at compile time, getting the size of an array tends to trivial. We don't need sizeof because we can figure out the size by looking at our declaration.

C++ provides heap arrays, as in

int len;
scanf("%d", &len);
int *arr = new int[len];

but since this involves pointers instead of stack arrays, we have to store the size in a variable which we pass around manually.

Daniel Lubarov
  • 7,796
  • 1
  • 37
  • 56
  • 2
    Strictly, these "heap arrays" aren't much different to C arrays - especially not for int, or other types C++ considers "Plain Old Data". It's "syntactic sugar" for a malloc, except for constructor handling, which with POD is irrelevant anyway. Actually, strictly, C++ may use a separate heap for new - you shouldn't free what you new, or delete what you malloc, irrespective of constructor/destructor issues - but it's still just allocating a block of memory of at least the right size. –  Apr 19 '11 at 05:12
1

Arrays in C don't know how big they are, so yes, you have to do the sizeof array / sizeof array[0] trick to get the number of elements in an array.

As for the segfault issue, I'm guessing that you exceeded your stack size by attempting to allocate 10000000 * sizeof int bytes. A rule of thumb is that if you need more than a few hundred bytes, allocate it dynamically using malloc or calloc instead of trying to create a large auto variable:

int r = 10000000;
int *tests = malloc(sizeof *test * r);

Note that you can treat tests as though it were an array type in most circumstances (i.e., you can subscript it, you can pass it to any function that expects an array, etc.), but it is not an array type; it is a pointer type, so the sizeof tests / sizeof tests[0] trick won't work.

John Bode
  • 119,563
  • 19
  • 122
  • 198
0

Stack Overflow! Try allocating on the heap instead of the stack.

Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
J T
  • 4,946
  • 5
  • 28
  • 38
0

I suspect that it is because of integer overflow. Try printing the value using a printf:

printf("%d", 10000000);

If it prints a negative number - that is the issue.

Dakshinamurthy Karra
  • 5,353
  • 1
  • 17
  • 28
  • printf ("%i\n", 10000000); printf ("%i\n", 100000000); printf ("Size: %i\n", sizeof(int)); 10000000 100000000 Size: 4 – user697111 Apr 19 '11 at 04:50
  • A 32 bit integer will not overflow for this. A 24 bit signed integer would fail (just - 10 million would be OK as unsigned 24 bit), but the math to convert to a store location using 24 bit addresses (except for arrays of single-byte values) would fail. Architectures with 24 bit types are rare, but there were at least a few in the past. –  Apr 19 '11 at 04:55