Topic 65 of 100 Arrays and Strings in C Interactive Tutorial

Finding the Size of an Array in C: Length Calculation Techniques

11 mins read Last updated: 22 Aug 2026 28,300 views
C Compiler 0.00%

What is Finding the Size of an Array in C? Core Concept & Direct Summary

Core Objective & Problem Statement

How do you calculate array length using the `sizeof(arr) / sizeof(arr[0])` macro idiom, and why does it fail for function parameters?

Direct Answer Summary

Here's a question that looks trivial and isn't: how long is my array?

In some languages you'd write array.length and move on. In C, there's no such property — an array is just a block of memory, and nothing in it records how many elements it holds. No header, no metadata, no hidden count. Just bytes.

So C programmers use a technique, and that technique has one famous failure case that catches essentially every beginner exactly once. This tutorial covers the idiom, the failure, why the failure happens, and the safe patterns to use instead. Get this right and a whole category of "my loop went crazy" bugs disappears from your life.

(Suggested image: the hero graphic — an array of 5 boxes with a measuring tape spanning it, and the formula sizeof(arr) / sizeof(arr[0]) = 20 / 4 = 5 shown below)


How Does Finding the Size of an Array in C Work? In-Depth Mechanics & Architecture

Start With the Core Fact: Arrays Don't Know Their Size

main.c
Run Online
int marks[5] = {
    45, 62, 78, 34, 90
}
;

Ask C "how many elements is this?" and the honest answer is: it doesn't know. The array is 20 bytes of stack memory holding five 4-byte integers. Nothing in those bytes says "there are five of me."

The size exists only in the source code — in the declaration [5]. During compilation, the compiler knows. At runtime, the running program does not.

This is why:

  • You can't do marks.length or marks.size()
  • You must pass the count along with the array when handing it to functions
  • C relies on conventions (like the '\0' terminator in strings) whenever it needs to find the end of something at runtime

Now, the good news: at the point where you declared the array, the compiler can still tell you the size — and that's where sizeof comes in.


The Standard Idiom: sizeof(arr) / sizeof(arr[0])

main.c
Run Online
#include <stdio.h>
int main(void) {
    int marks[] = {
        45, 62, 78, 34, 90
    };
    printf("Total bytes  : %zu\n", sizeof(marks));
    printf("Bytes/element: %zu\n", sizeof(marks[0]));
    printf("Element count: %zu\n", sizeof(marks) / sizeof(marks[0]));
    return 0;
}

Output:

main.c
Run Online
Total bytes : 20Bytes/element: 4Element count: 5

The logic is beautifully simple:

  • sizeof(marks) → the whole array's size in bytes (20 = 5 × 4)
  • sizeof(marks[0]) → one element's size in bytes (4)
  • Divide → 5

And it works for any element type without you changing a thing:

main.c
Run Online
float prices[] = {
    1.5, 2.5, 3.5
}
;
double big[] = {
    1.0, 2.0
}
;
char letters[] = {
    'a', 'b', 'c', 'd'
}
;
struct Point pts[10];
printf("%zu\n", sizeof(prices) / sizeof(prices[0]));
// 3printf("%zu\n", sizeof(big)     / sizeof(big[0]));
// 2printf("%zu\n", sizeof(letters) / sizeof(letters[0]));
// 4printf("%zu\n", sizeof(pts)     / sizeof(pts[0]));
// 10

You never need to know the type's byte size — the division cancels it out. That's why this idiom beats hard-coding 4 or 8.

Note the %zu format specifier — from our format specifiers tutorial. sizeof produces a size_t (an unsigned type), so %zu is the correct specifier. Using %d happens to work on many systems but is technically wrong and warns with -Wformat.

(Suggested image: the division shown visually — a 20-byte array strip being cut into 4-byte chunks, yielding 5 chunks)


Making It Readable: A Macro

Since you'll write this constantly, most codebases define a shorthand:

main.c
Run Online
#define ARRAY_SIZE(arr)(sizeof(arr) / sizeof((arr)[0]))

Then:

main.c
Run Online
int marks[] = {
    45, 62, 78, 34, 90
}
;
for (int i = 0;
i < ARRAY_SIZE(marks);
i++) {
    printf("%d ", marks[i]);
}

Two important cautions about this macro:

  1. The parentheses are essential.#define SIZE(a) sizeof(a) / sizeof(a[0]) without wrapping, used in an expression like n * SIZE(a), would expand to n * sizeof(a) / sizeof(a[0]) — which happens to work here due to left-to-right evaluation of * and /, but the principle still applies: always fully parenthesize macros. The wrapper above is the safe form.
  2. This macro has the exact same limitation as the raw idiom — it uses sizeof, so it fails anywhere sizeof fails. A macro can't magically fix the decay problem (coming next). Many experienced C programmers deliberately avoid this macro precisely because it makes the failure mode look safe when it isn't.

The Famous Failure: It Breaks Inside Functions

Here's the trap. This code looks perfectly reasonable — and it's wrong:

main.c
Run Online
#include <stdio.h>
void printArray(int arr[]) {
    int n = sizeof(arr) / sizeof(arr[0]);
    // ✗ WRONG!
    printf("Calculated size: %d\n", n);
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    putchar('\n');
}
int main(void) {
    int marks[5] = {
        45, 62, 78, 34, 90
    };
    printf("Real size in main: %zu\n", sizeof(marks) / sizeof(marks[0]));
    printArray(marks);
    return 0;
}

Typical output on a 64-bit system:

main.c
Run Online
Real size in main: 5Calculated size: 245 62

Two elements?! Where did 5 go?

The explanation: array-to-pointer decay. When you pass an array to a function, C does not pass the array. It passes a pointer to the first element. Inside printArray, arr is an int * — not an array. So:

  • sizeof(arr) = size of a pointer = 8 bytes (on 64-bit systems)
  • sizeof(arr[0]) = 4 bytes
  • 8 / 4 = 2 ← the bogus answer

That "2" is pure coincidence, and it's why this bug is so sneaky: sometimes the number looks plausible. On a 32-bit system you'd get 4 / 4 = 1. On other element types you'd get different nonsense. sizeof on a function parameter never gives the array size — only the pointer size.

(Suggested image: the decay diagram — a full array of 5 boxes in main() vs the function receiving a single small pointer box, with the "20 bytes → 8 bytes" label showing where the size information is lost)

Why Does Decay Happen?

Because that's how C was designed. Array parameters are really pointer parameters — void f(int arr[]) and void f(int *arr) are exactly the same declaration to the compiler (this is why our prototypes tutorial showed both forms as equivalent). The bracket syntax is just friendlier notation for "pointer to the first element."

It's an efficiency choice: copying an entire array on every function call would be expensive. Passing an address costs one word.


The Safe Pattern: Pass the Size Explicitly

Since the function can't know the size, you tell it:

main.c
Run Online
#include <stdio.h>
void printArray(int arr[], int n) {
    // size as a separate parameter    for (int i = 0; i < n; i++) {        printf("%d ", arr[i]);    }    putchar('\n');}
    int main(void) {
        int marks[] = {
            45, 62, 78, 34, 90
        };
        int n = sizeof(marks) / sizeof(marks[0]);
        // sizeof only works HERE
        printArray(marks, n);
        // size travels with the array    return 0;}

Output:

This is the universal C convention: whenever an array goes into a function, its length goes along with it as a separate argument. You'll see this in qsort(), memcpy(), fwrite(), and essentially every standard library function that takes an array. It's not a workaround — it's the idiom.

(Suggested image: "the size travels with the array" — a function signature card showing int arr[], int n with an arrow from main's sizeof calculation)


Sizing Strings: sizeof vs strlen()

Character arrays have their own size confusion, because there are two different "sizes" that matter.

main.c
Run Online
#include <stdio.h>
#include <string.h>
int main(void) {
    char name[50] = "Ravi";
    printf("sizeof : %zu\n", sizeof(name));
    // 50 — the array's capacity    printf("strlen : %zu\n", strlen(name));    // 4  — the string's length
    return 0;
}

Two totally different numbers, both correct:

sizeof(name)strlen(name)
AnswersHow big is the container?How long is the text?
Result here504
Determined atCompile timeRuntime (counts until '\0')
Includes '\0'?Yes (it's part of the array)No
Works onAny arrayOnly null-terminated strings

strlen walks the characters until it finds the terminating '\0' — which is exactly the runtime convention C uses to make strings self-describing (since arrays themselves aren't). That's why forgetting the '\0' breaks string functions: they run past the end hunting for a terminator that isn't there.

Practical consequences:

  • Reserving space: use sizeof → char line[100]; fits up to 99 characters + terminator
  • Measuring user input: use strlen → how many characters did they actually type?
  • Reading input safely: fgets(name, sizeof(name), stdin) — the sizeof gives the buffer capacity, which is exactly what fgets needs

That last point is a nice illustration of the difference mattering: fgets wants the capacity (how much room exists), because it's guarding against overflow. It doesn't care about the current text length.


Other Techniques You'll See

Sentinel values (when there's no size to pass)

Some data has a natural "end marker" instead of a count. Strings use '\0'; other arrays might use -1, 0, or a special constant:

main.c
Run Online
int readings[] = {
    23, 45, 67, 89, -1
}
;
// -1 marks the end
int i = 0;
while (readings[i] != -1) {
    printf("%d ", readings[i]);
    i++;
}

This is a sentinel-controlled loop — the same pattern from our while-loop tutorial. It works, but it costs you the ability to store the sentinel value as real data, and skipping the sentinel by accident runs off the end. Prefer an explicit count when you can.

Variables tracking count alongside the array

In practice, most real code stores the count next to the array and never recomputes it:

main.c
Run Online
int marks[MAX];
int markCount = 0;
// adding a value:marks[markCount++] = newMark;
// later, everywhere:for (int i = 0; i < markCount; i++) { ... }

This handles a common situation the sizeof idiom can't: an array with more capacity than current contents. sizeof(marks) / sizeof(marks[0]) gives you MAX (the room), never the number you've actually filled. When the distinction matters (and it usually does with user input), you track the count yourself.

sizeof on pointers: never the answer

main.c
Run Online
int *ptr = marks;
sizeof(ptr) // 8 — pointer size, NOT 20sizeof(*ptr)         // 4 — one int (the pointed-to type)

Once you're holding a pointer, sizeof tells you about the pointer, not the array behind it. There's no portable way to recover an array's length from a bare pointer — the information is simply gone. (A gentle preview: this is why the Pointers cluster will keep saying "pass the size with the pointer.")

(Suggested image: a decision flowchart — "Is this an array in its declaring scope? → sizeof works. Is it a function parameter or pointer? → pass the size in. Is it a string? → strlen.")


Putting It All Together: A Safe Array Library

Here's how a small, correct set of array functions looks in practice:

main.c
Run Online
#include <stdio.h>
#define MAX_MARKS 100
// Every array function takes the count explicitly
void printArray(const int arr[], int n);
int findMax(const int arr[], int n);
int findIndex(const int arr[], int n, int target);
double average(const int arr[], int n);
int main(void) {
    int marks[MAX_MARKS];
    int count = 0;
    int input;
    puts("Enter marks (negative to finish):");
    while (count < MAX_MARKS) {
        printf("Mark %d: ", count + 1);
        scanf("%d", &input);
        if (input < 0) break;
        marks[count++] = input;
        // fill and count in one step
    }
    if (count == 0) {
        puts("No marks entered.");
        return 0;
    }
    printf("\nYou entered %d marks.\n", count);
    printArray(marks, count);
    printf("Highest : %d\n", findMax(marks, count));
    printf("Average : %.2f\n", average(marks, count));
    int idx = findIndex(marks, count, 78);
    if (idx != -1) {
        printf("78 found at position %d\n", idx);
    } else {
        puts("78 not found.");
    }
    return 0;
}
void printArray(const int arr[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    putchar('\n');
}
int findMax(const int arr[], int n) {
    int max = arr[0];
    for (int i = 1; i < n; i++) {
        if (arr[i] > max) max = arr[i];
    }
    return max;
}
int findIndex(const int arr[], int n, int target) {
    for (int i = 0; i < n; i++) {
        if (arr[i] == target) return i;
    }
    return -1;
    // -1 means "not found"
}
double average(const int arr[], int n) {
    int total = 0;
    for (int i = 0; i < n; i++) total += arr[i];
    return(double)total / n;
    // cast for a proper division
}

Sample Run:

main.c
Run Online
Enter marks(negative to finish):
Mark 1: 78
Mark 2: 85
Mark 3: 62
Mark 4: 91
Mark 5: -1
You entered 4 marks.
78 85 62 91
Highest : 91
Average : 79.00
78 found at position 0

Three things to notice:

  1. Every function takes the count — printArray(marks, count), findMax(marks, count). Nowhere does any of them try sizeof on the parameter.
  2. const on the array parameters — it promises the function won't modify your data, which is careful, professional C. The compiler enforces it.
  3. The count variable pattern — count grows with each input, handling the "capacity 100, contents 4" distinction that sizeof alone can't express.

That's the pattern. Write it a few times and array functions will stop feeling like a trap.


Common Size Mistakes

  1. Using sizeof on an array parameter inside a function — the big one. You get the pointer size (8 or 4), not the element count. Always pass the count separately.
  2. sizeof on a pointer — same trap, different disguise: int *p = arr; sizeof(p) is the pointer, never the array.
  3. Confusing sizeof and strlen for strings — capacity vs content length. The source of endless off-by-one confusion in string code.
  4. Forgetting %zu when printing sizeof results — %d is technically wrong for size_t and warns under -Wformat.
  5. Assuming the macro version is magic — ARRAY_SIZE(arr) is still sizeof, so it breaks in exactly the same places. Never use it on a parameter.
  6. Expecting to count initialized elements — sizeof(arr)/sizeof(arr[0]) always returns the declared capacity, not how many slots you've filled. Unfilled slots count too (as zeros or garbage).
  7. Trying to recover size from a bare pointer at runtime — impossible in portable C. If you need it later, store it or pass it; don't hope.

(Suggested image: "7 Array Size Mistakes" checklist graphic — consistent with the series)


Final Thoughts

The size of an array in C comes down to one idea: the size lives in the source code, not in the data. Where the compiler can still see your declaration, sizeof(arr) / sizeof(arr[0]) hands you the count with perfect accuracy. The moment the array crosses a function boundary, it becomes a pointer and the size information is gone — so you carry it across yourself, as a parameter.

Everything else follows from that: strlen for strings, a tracking variable for partially filled arrays, sentinels when a marker is the natural design, const int arr[], int n in every array function you write. Get the habit right and you'll never be surprised by a "why did my loop only process 2 elements?" bug again.

Next in this cluster: passing arrays to functions properly — where these size conventions get their full build-out, along with const parameters and multi-file array handling.


Runnable C Code Example & Practical Implementation

main.c
Run Online
#include <stdio.h>
#define ARRAY_SIZE(arr)(sizeof(arr) / sizeof((arr)[0]))
void printSize(int arr[]) {
    // WARNING: arr is a pointer here!
    printf("Inside function: sizeof(arr) = %zu (Pointer size!)\
", sizeof(arr));
}
int main() {
    int data[8] = {
        1, 2, 3, 4, 5, 6, 7, 8
    };
    printf("In main: Array length = %zu\
", ARRAY_SIZE(data));
    printSize(data);
    return 0;
}

Key Takeaways, Best Practices & Memory Safety Rules

Best Practice & Key Takeaways
Never use sizeof to determine array size on function parameters; always pass size explicitly as a size_t argument.

Frequently Asked Questions & Technical Interview Insights

Technical Interview & Viva Questions

Frequently asked C programming interview questions
Q

Q: Why does `sizeof(arr) / sizeof(arr[0])` yield `2` or `1` inside a function on a 64-bit machine?

A: Because inside the function parameter `int arr[]`, `arr` decays into a pointer (`int*`). `sizeof(int*)` is 8 bytes, and `sizeof(int)` is 4 bytes: $8 / 4 = 2$.
Q

Q: How do you pass array size portably?

A: Pass `size_t count` as a separate argument alongside the array pointer.

Related Tools, Tutorials & Authoritative References

Recommended Interactive Tools

Authoritative Standards & Citations