What is Array Parameters Are Pointers- C Programming Training Institute In Hyderabad

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

Free C Programming Course · Chapter 8 · Pointers

Array Parameters Are Pointers

Discover why sizeof on an array parameter in C returns the size of a pointer, how to detect the bug with compiler warnings, and how embedded C programming code stays safe by passing the length explicitly.

4/8
Bytes in a pointer on 32/64-bit targets
1
Macro to count elements safely
3
Warnings GCC raises for the bug

What You Will Learn

In the previous lecture of this free C programming course we saw that a function receives only a pointer when you pass it an array. This lecture proves that claim with measurements and shows the consequence: the sizeof array parameter in C trap. If you want to write reliable embedded C programming code for sensors, UART drivers and bootloaders, you need to know exactly where array sizes survive and where they disappear.

  • How sizeof behaves for a real array versus an array-looking parameter.
  • Why the answer inside the function is the pointer size, whatever size you write in the brackets.
  • What older textbooks mean when they show a pointer size of 2 bytes, and what you will see on modern machines and microcontrollers.
  • How to read the GCC warning that catches this bug before it ships.
  • The standard ARRAY_LEN macro, and where it may and may not be used.

Prerequisites

Finish the lecture on passing arrays to functions first. You should also know the fixed-width types from stdint.h such as uint8_t and uint16_t, and how sizeof works on variables and types.

The sizeof Array Parameter in C Trap

Look at this idea. In main() you declare an array of eight bytes. sizeof on that array gives 8, because the compiler knows the full array type. Now you pass the array to a function whose parameter is written as const uint8_t buf[8]. It certainly looks like the function receives eight bytes. It does not. The parameter is a pointer, so sizeof(buf) inside the function is the size of a pointer, not eight.

The same holds for any element type. An array of eight uint16_t values has sizeof equal to 16 in the caller, and an array of eight float values has 32. Inside a function that takes them as parameters, all three sizeof results collapse to the same number, because every data pointer on a given machine has the same size.

Same Name, Two Different Types

In main()rx is uint8_t[8]→ sizeof(rx) = 8
In main()adc is uint16_t[8]→ sizeof(adc) = 16
In main()temp is float[8]→ sizeof(temp) = 32
In calleeb, w, f are all pointers→ sizeof = pointer size

Pointer Size on Different Targets

PlatformTypical pointer sizeWhere you meet it
Old 16-bit DOS compilers2 bytesClassic textbooks, which print 2 for pointer sizes
32-bit ARM Cortex-M, RISC-V RV324 bytesSTM32, nRF, ESP32-C3 style microcontrollers
64-bit Linux on x86-64 or AArch648 bytesYour laptop, Raspberry Pi with a 64-bit OS

If you read an older C book and see the number 2 for pointer size, that reflects the compiler of its time. Never memorise the number. Remember the rule: it is the size of an address on the machine you build for, and it does not depend on what the pointer points to.

Build and Run the Experiment

The program below measures the same three arrays in both places. It also contains the correct approach, a checksum function that receives a pointer and a length. Save it as ep_sizeof_trap.c.

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>

#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))

/* Looks like it receives an array. It does not. */
static void wrong_way(const uint8_t b[8], const uint16_t w[8], const float f[8])
{
    printf("inside wrong_way : sizeof(b)=%zu  sizeof(w)=%zu  sizeof(f)=%zu\n",
           sizeof(b), sizeof(w), sizeof(f));
}

/* The honest version: pointer + length. */
static uint8_t checksum8(const uint8_t *buf, size_t len)
{
    unsigned sum = 0;
    for (size_t i = 0; i < len; i++) {
        sum += buf[i];
    }
    return (uint8_t)(sum & 0xFFu);
}

int main(void)
{
    uint8_t  rx[8]    = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80};
    uint16_t adc[8]   = {100, 200, 300, 400, 500, 600, 700, 800};
    float    temp[8]  = {20.5f, 21.0f, 21.5f, 22.0f, 22.5f, 23.0f, 23.5f, 24.0f};

    printf("inside main      : sizeof(rx)=%zu  sizeof(adc)=%zu  sizeof(temp)=%zu\n",
           sizeof(rx), sizeof(adc), sizeof(temp));
    printf("inside main      : element counts = %zu, %zu, %zu\n",
           ARRAY_LEN(rx), ARRAY_LEN(adc), ARRAY_LEN(temp));

    wrong_way(rx, adc, temp);

    printf("checksum8 over %zu bytes = 0x%02X\n", ARRAY_LEN(rx),
           checksum8(rx, ARRAY_LEN(rx)));
    return 0;
}
gcc -std=c11 -Wall -Wextra -o ep_sizeof_trap ep_sizeof_trap.c
./ep_sizeof_trap

Expected output on a 64-bit Linux machine:

inside main      : sizeof(rx)=8  sizeof(adc)=16  sizeof(temp)=32
inside main      : element counts = 8, 8, 8
inside wrong_way : sizeof(b)=8  sizeof(w)=8  sizeof(f)=8
checksum8 over 8 bytes = 0x40

On a 32-bit microcontroller target the third line would show 4 for each value. The first two lines are identical on every platform, because those sizes come from the array types.

What the Compiler Tells You

During compilation GCC prints a warning for each of the three parameters. The message has this shape:

warning: 'sizeof' on array function parameter 'b' will return size of
'const uint8_t *' [-Wsizeof-array-argument]

This is the compiler telling you, in plain words, that your array parameter is really a pointer. Treat that warning as an error in your build flags for firmware projects. It is one of the few warnings that always indicates a genuine logic bug.

Checking the Checksum by Hand

The bytes are 0x10 through 0x80 in steps of 0x10. Their sum is 0x240. Keeping only the low eight bits gives 0x40, which matches the program output. Working such a result out by hand is a good habit when you test parsing code.

The Safe Pattern: Pointer Plus Length

Since the callee cannot recover the size, the caller must supply it. The convention in nearly every C API, from the C library to vendor HAL drivers, is a pointer followed by a length. The caller computes the length where the array type is still visible, using the standard element-count macro:

#define ARRAY_LEN(a) (sizeof(a) / sizeof((a)[0]))

This macro divides the total bytes by the bytes of one element. It is correct only where a is a genuine array. If you apply it to a pointer parameter it silently returns the wrong number: on a 64-bit machine with a uint8_t * it gives 8, and with an int * it gives 2. Neither number has anything to do with the real buffer.

Where ARRAY_LEN Works

Safeuint8_t rx[8]; ARRAY_LEN(rx)→ 8
Safestatic table at file scope→ element count
WrongARRAY_LEN(buf) inside a function with parameter buf→ pointer size divided by element size

Documenting the Minimum Size With static

C99 gives you a way to state the expected minimum length in a parameter: const uint8_t buf[static 8] means the caller promises at least eight accessible elements. It does not change the fact that the parameter is a pointer, but compilers such as GCC and Clang can use it to warn when a caller passes a visibly smaller array. Use it for fixed-size records like a MAC address or a six-byte header.

Real-World Impact in Firmware

  • Silent truncation: a helper that loops to sizeof(buf) processes only 4 or 8 bytes of a large frame, and the rest of the data is ignored, which can look like a flaky communication link.
  • Buffer overrun: a copy loop that trusts a wrong length can write past the end of a stack buffer, which on a microcontroller usually corrupts a neighbouring variable instead of crashing immediately, making it very hard to debug.
  • Code review smell: any sizeof of a parameter name deserves an immediate second look.

Common Mistakes and Troubleshooting

MistakeWhat happensFix
Using sizeof(param) as a lengthReturns pointer sizePass the length as an argument
Using ARRAY_LEN on a parameterWrong count without any errorCompute the count in the caller
Ignoring -Wsizeof-array-argumentBug ships to hardwareBuild with -Wall -Werror for firmware
Assuming pointer size is 2 or 4 everywhereCode breaks when portedNever hard-code it; use sizeof(void *) if you need it

Best Practices, Performance and Security

  • Use the (pointer, length) pair as your default function signature for buffers.
  • Use size_t for the length and print it with %zu.
  • Compute lengths once, close to where the array is defined, and keep them in a named constant or macro.
  • Check lengths before copying. In networked or serial firmware, a length that came from outside must be validated against the buffer capacity, because mishandled lengths are the classic source of memory-safety vulnerabilities.
  • Performance note: passing a pointer and a length costs two machine words regardless of buffer size, so there is nothing to optimise away.

Key Takeaways

  • sizeof of a real array gives the whole array; sizeof of an array parameter gives one pointer.
  • The number in the brackets of a parameter is ignored by the compiler.
  • Always send the element count along with the pointer.
  • Treat -Wsizeof-array-argument as a bug report, not noise.

Conclusion

Understanding the sizeof array parameter in C behaviour is a rite of passage. Once you have seen the numbers come out identical for a byte array, a halfword array and a float array, you will never confuse a parameter with an array again. Write your interfaces as pointer plus length, count elements where the array is visible, and let the compiler warnings guard the rest. In the next lecture we move from one dimension to two and see what a function receives when you hand it a matrix.

Suggested Images for This Lecture

  • Side-by-side graphic of sizeof in main and in the callee. Alt text: “sizeof array parameter in C compared between caller and callee in a free C programming course”.
  • Terminal screenshot with the -Wsizeof-array-argument warning. Alt text: “gcc warning for sizeof array parameter in C embedded C programming”.
  • Table of pointer sizes on 16-bit, 32-bit and 64-bit targets. Alt text: “pointer size on Cortex-M versus x86-64 for C programming for embedded systems”.

Frequently Asked Questions

Why does sizeof give the pointer size for my array parameter?

Because the parameter is a pointer. The compiler rewrites an array-style parameter into a pointer at the function boundary, so the array type is gone.

Does the number inside the brackets of a parameter do anything?

For a one-dimensional parameter it has no effect on the type. Only the C99 static form gives the compiler a minimum size hint to check callers against.

How do I get the number of elements inside a function?

You cannot compute it from the pointer. Pass it as an additional argument from the caller, which still sees the real array.

Is the ARRAY_LEN macro safe to use?

It is safe on real arrays, and wrong on pointers. Use it only in the scope where the array is declared, never on a function parameter.

Why did my textbook print 2 for pointer size?

It was written for a 16-bit compiler. On 32-bit microcontrollers you will see 4 and on 64-bit Linux you will see 8.

Can a struct hold the array and its length together?

Yes. A struct containing a pointer and a count is a common way to bundle a buffer description, and many embedded libraries use exactly that pattern.

Continue the Free C Tutorial

Next up: how a function receives a two-dimensional array and why the column count must be written down. Keep going with our free embedded C course.

Need Help or More Information?

Questions about this free C programming course, embedded C training or career guidance? Get in touch.

2 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *