What is Dereferencing Pointer to Array- Best C Programming Course

Need Help or More Information?

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

PREV_LEC NEXT_LEC

Free Embedded C Course · Pointers · Lecture 22

Dereferencing Pointer to Array

A free c tutorial on what *ptr really returns when ptr points to an array, with sizes, array decay and a fixed-size buffer demo you can run today.

3
Dereference levels
20
sizeof(*whole) in bytes
1
Compile-time size check

What You Will Learn

  • What you get when you dereference a pointer to an array, and why it is the array itself
  • How the array result decays into a pointer, and why sizeof still sees the full size
  • Two correct ways to read an element: (*whole)[i] and whole[0][i]
  • Why *whole[i] is a trap
  • How to pass a fixed-size buffer to a function so the compiler checks its length

Prerequisites

  • The previous lecture on declaring a pointer to an array
  • Basic dereferencing: *p gives the object p points to
  • GCC on Linux or an embedded ARM toolchain

What Dereferencing a Pointer to an Array Gives You

This free c tutorial answers one question that confuses almost every learner: if whole points to an array of five integers, what is *whole? The rule is the same as for any pointer. Dereferencing a pointer to type T gives you an object of type T. Here T is int[5], so *whole is the five-integer array itself, not a single number.

An array that appears in an expression is converted to a pointer to its first element. That conversion is called decay, and it explains why *whole behaves like an address even though its type is an array. Dereference once more and you finally arrive at an integer.

Three levels of dereferencing
whole type int (*)[5] pointer to an array of 5 ints
*whole type int[5] the array, which decays to int * (address of element 0)
**whole type int the first element, here the value 3
ExpressionTypeMeaningsizeof (64-bit)
wholeint (*)[5]Pointer to the whole array8
*wholeint[5]The array; decays to the first element’s address20
**wholeintThe first element4
(*whole)[2]intThe third element4

sizeof Is the Exception to Decay

Decay happens almost everywhere an array is used, but not when the array is the operand of sizeof or of the address operator &. That is why sizeof *whole gives 20, the full array, even though a plain use of *whole in an expression would behave like a pointer. It is also why *whole and samples compare equal when you cast both to void *: they name the same first byte.

Reading Elements Through a Pointer to an Array

There are two clean spellings for element i. The first applies the star to whole to get the array, then subscripts it: (*whole)[i]. The second treats whole like a pointer to the first of several arrays and takes array number zero: whole[0][i]. Both give the same result, and the second form is the one that generalises to many arrays, which is the key to two-dimensional tables in later lectures.

The parentheses trap

*whole[i] does not mean the same as (*whole)[i]. The subscript binds first, so whole[i] moves forward by i whole arrays (20 bytes each), and the star is applied afterwards. For any i other than zero you read memory outside the array. Always write the parentheses.

Demo: Dereferencing and Sizes in Action

Every free c tutorial should let you run the code, so here is a complete program. It reads elements in both styles, compares addresses, prints the three sizes from the table, and then passes a buffer to a function that expects a fixed-size array. That last part previews the practical payoff.

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

static void clear_frame(uint8_t (*frame)[8])
{
    memset(*frame, 0, sizeof *frame);
}

int main(void)
{
    int samples[5] = {3, 5, 6, 7, 9};
    int (*whole)[5] = &samples;

    printf("(*whole)[2]  = %d\n", (*whole)[2]);
    printf("whole[0][3]  = %d\n", whole[0][3]);
    printf("*whole == samples : %s\n", (void *)*whole == (void *)samples ? "yes" : "no");
    printf("sizeof(whole)   = %zu\n", sizeof whole);
    printf("sizeof(*whole)  = %zu\n", sizeof *whole);
    printf("sizeof(**whole) = %zu\n", sizeof **whole);

    uint8_t frame[8] = {1, 2, 3, 4, 5, 6, 7, 8};
    clear_frame(&frame);
    printf("frame[0]=%u frame[7]=%u\n", frame[0], frame[7]);
    return 0;
}
gcc -std=c11 -Wall -Wextra -o e22 e22.c
./e22

Expected output on a 64-bit Linux machine:

(*whole)[2]  = 6
whole[0][3]  = 7
*whole == samples : yes
sizeof(whole)   = 8
sizeof(*whole)  = 20
sizeof(**whole) = 4
frame[0]=0 frame[7]=0

Walk through it line by line. The first two lines show both spellings reaching the third and fourth elements of {3, 5, 6, 7, 9}. The comparison line proves the array and the array pointer’s target start at the same byte. The three sizes match the table: 8 for the pointer, 20 for the array it points to, and 4 for one element. The final line shows that clear_frame zeroed all eight bytes.

Passing Fixed-Size Buffers to Functions

This part of the free c tutorial is where the theory pays off. The usual way to hand a buffer to a function is a pointer plus a length. It works, but the compiler cannot tell whether the length you pass is right. A pointer to an array moves the size into the type, so the check happens at build time. In clear_frame above, sizeof *frame is 8 because the parameter type says so; no length argument can go stale.

ApproachCompiler checks the size?Typical cost
void f(uint8_t *buf, size_t len)No, the length is trustedOne extra argument
void f(uint8_t (*buf)[8])Yes, a wrong array length is a type errorCaller must write &frame
void f(uint8_t buf[8])No, it is rewritten to uint8_t *bufLooks safe but is not

Try passing the wrong size to see the protection working:

uint8_t small[4] = {1, 2, 3, 4};
clear_frame(&small);        /* clear_frame expects uint8_t (*)[8] */

GCC 13 reports it like this (abridged):

warning: passing argument 1 of 'clear_frame' from incompatible pointer type [-Wincompatible-pointer-types]
note: expected 'uint8_t (*)[8]' but argument is of type 'uint8_t (*)[4]'

A four-byte buffer is rejected at compile time. With the pointer-plus-length style the same mistake would build cleanly and overwrite four bytes of whatever sits after the buffer.

Free C Tutorial: Common Dereferencing Mistakes

MistakeSymptomFix
Writing *whole[i] for (*whole)[i]Wrong values or reads far outside the arrayAlways parenthesise the star
Expecting *whole to be an intType mismatch warning in printf("%d", *whole)Dereference twice, or index with (*whole)[0]
Using sizeof(whole) to get the array sizePrints 8 instead of 20Use sizeof *whole
Forgetting & at the call siteIncompatible pointer type warningPass &frame
Casting away the warningHidden length mismatch bugsFix the type instead of casting

Free C Tutorial Best Practices and Security

  • Use sizeof *ptr instead of repeating the length, so the number cannot drift away from the type.
  • Write (*whole)[i] with parentheses every time; add a short comment if a colleague might misread it.
  • Use a typedef for frame types shared across files, and keep the macro that defines the length in one header.
  • Compile with -Wall -Wextra and treat -Wincompatible-pointer-types as an error.

This free c tutorial would be incomplete without a word on cost. For performance, dereferencing a pointer to an array costs nothing extra; the compiler resolves the decay at build time and emits the same load instruction as for a plain element pointer. For security, remember that the fixed length lives in the type only. If the pointer itself is wrong, or an index is out of range, the compiler cannot help, so validate indexes that come from the outside world such as a received packet.

Real-World Uses

  • Protocol frames: a CAN driver exposes send(uint8_t (*payload)[8]) so every caller supplies exactly the classic CAN data size.
  • Block processing: an audio routine takes int16_t (*block)[64] and can use sizeof *block for its loop bounds.
  • Row access in tables: a pointer to one row of a keypad map lets you scan columns without copying the data.

Free C Tutorial Key Takeaways and Conclusion

  • Dereferencing a pointer to an array gives the array, which decays to the address of its first element.
  • sizeof and & are the two places where an array does not decay.
  • Read elements with (*whole)[i] or whole[0][i], never *whole[i].
  • Taking a pointer to a fixed-size array as a parameter lets the compiler reject wrong-sized buffers.

That wraps up the dereferencing story. If you are following this free c tutorial from the start, you now understand every level between a pointer to an array and the integer inside it. Together with the free embedded c course lectures on pointers and arrays, this gives you the vocabulary to read driver code that passes buffers around by type. The next lecture applies the same idea to two-dimensional arrays, where every row is itself an array.

Frequently Asked Questions

What does *whole return when whole points to an array?

It returns the array itself, whose type is int[5]. In most expressions that array decays to a pointer to its first element.

Why does sizeof *whole give 20?

Because sizeof is one of the places where an array does not decay. It reports the size of the full array, five ints of four bytes each.

Are (*whole)[2] and whole[0][2] the same?

Yes. Both read the third element. The second form treats whole as a pointer to the first of several arrays and selects array number zero.

What is wrong with *whole[2]?

The subscript applies first, so it steps forward two whole arrays and then dereferences, reading memory outside samples.

Why not just pass a pointer and a length?

You can, but the compiler cannot verify that the length matches the buffer. A pointer to a fixed-size array makes the length part of the type and checks it at build time.

Does void f(uint8_t buf[8]) enforce the size?

No. The compiler rewrites that parameter to uint8_t *buf, so any buffer is accepted and sizeof buf is just the pointer size.

Is decay a run-time operation?

No. It is a compile-time conversion, so it adds no instructions beyond the address calculation you would write by hand.

Next Up in the Free C Tutorial

Two-dimensional arrays are arrays of arrays. Continue the free c programming course to see how they sit in memory.

PREV_LEC NEXT_LEC

Need Help or More Information?

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

1 Comment

Leave a Reply

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