Concepts / Using array with C-Style Functions and Comparing with Other Containers

Using array with C-Style Functions and Comparing with Other Containers

In that style, the parameter is declared as a pointer rather than as an array.

  • Programming

A Hand-Off Question to Predict

Sometimes a program has a fixed-size array and needs to give it to a function that was written in the older C style. In that style, the parameter is declared as a pointer rather than as an array. The central rule is that an array can be explicitly passed to a C-style function that expects a pointer. The array does not have to stay in the calling code. It can be handed to a function whose parameter is a pointer, and that function can work with the elements through the pointer.

What do you think happens?

A caller creates an array of four ints, {1, 2, 3, 4}, and passes it to a function that doubles each element through a pointer. What does the caller print afterwards?

  • 1 2 3 4, because the function only received a copy

  • 2 4 6 8, because the function changed the caller's own elements

  • The program refuses to compile, because a pointer cannot receive an array

Reveal answer
Answer:

2 4 6 8, because the function changed the caller's own elements

The array is never copied. The function receives a pointer to the first element, and its writes go straight to the caller's array.

The rest of this article follows one question: when you make that hand-off, what does the function actually receive, and what does it lose along the way? Answering it is what makes array-to-pointer passing predictable instead of mysterious.

What Crosses the Function Boundary

Start with a concrete setup. A caller declares an array of four integers, then calls a function whose parameter is a pointer to int. Read the path step by step. The array is named in the call. At the point of the call, the name of the array is converted into a pointer to its first element. That pointer is what travels into the function's parameter.

values[0]1datapointer parametervalues[1]2values[2]3values[3]4points to first element
What does the function's pointer parameter hold after the array name is passed? It holds a reference to values[0], not the whole array.

The function never receives the whole array as one value. It receives a single pointer that refers to where the array begins. The array itself stays in the caller. What crosses the boundary is only the pointer to its first element. This is why the array is described as being passed to a function that expects a pointer: the expected argument type is the pointer, and the array name supplies it.

Reaching the Caller's Elements

Once the function has the pointer, it can reach each element by moving through the array from that starting point. The first element is at the position the pointer marks, and the others follow it. Using an index such as data[i] means 'the element i positions after the starting point.' Because the pointer leads back to the caller's own array, the function can read and change those elements. A change made through the pointer is visible to the caller once the function returns. The array was never copied.

data[0]offset 0values[0]1data[1]offset 1values[1]2data[2]offset 2values[2]3data[3]offset 3values[3]4same elementsame elementsame elementsame element
How does data[i] inside the function land on the same element as values[i] in the caller? Each index is an offset from the pointer's starting point.

The following example is original and matches the rule above. The function takes a pointer to int and a count. The caller passes the array name, which becomes the pointer, and passes the number of elements separately, because the pointer alone cannot provide it.

Code walkthrough
#include <stdio.h>

void double_all(int *data, int count) {
    for (int i = 0; i < count; i++) {
        data[i] = data[i] * 2;
    }
}

int main(void) {
    int values[4] = {1, 2, 3, 4};
    double_all(values, 4);
    for (int i = 0; i < 4; i++) {
        printf("%d ", values[i]);
    }
    printf("\n");
    return 0;
}
  1. 1
    void double_all(int *data, int count) declares a function that expects a pointer to int plus a separate count.
  2. 2
    The loop runs count times. Each data[i] refers to an element of the caller's array, not to a copy.
  3. 3
    In main, values is an array of four ints. Naming it in the call hands over a pointer to values[0].
  4. 4
    The call double_all(values, 4) passes that pointer and the count 4.
  5. 5
    After the function returns, the loop in main prints 2 4 6 8, because the changes were made to the original elements.
  • The parameter int *data is a pointer to int, the expected argument type.
  • The name values in the call becomes a pointer to values[0].
  • The count 4 travels separately because the pointer carries no length.
Output
2 4 6 8

What the Pointer Does Not Carry

The pointer gives the function access to the elements, but it does not carry the array length. The caller knew that the array had four elements. Once the array name has become a pointer, the function receives only the location of the first element. It has no built-in way to ask where the array ends. This is why the length must be passed separately, as the count parameter does in the example above.

values4 ints, length knowndatapointer to int onlycountpassed separatelyarray name becomes pointer
What does the caller know about the array before the call, and what does the function know after the call begins? The length is the piece that does not cross over with the pointer.

Mistakes When Passing Arrays

  • Common mistake

    Passing the array to a pointer parameter without passing its length

    What it looks like
    void double_all(int *data) with a loop that runs while the function guesses an end point, and the caller passing only values
    Why it fails

    The pointer carries no length, so the function has nothing reliable to stop at.

    Do this instead

    Pass the number of elements as its own argument, such as double_all(values, 4), and use that count in the loop.

  • Common mistake

    Passing a count that does not match the array

    What it looks like
    int values[4] = {1, 2, 3, 4}; double_all(values, 6);
    Why it fails

    The function trusts the count it is given. With 6, it reaches past the four elements the caller actually declared.

    Do this instead

    Keep the count tied to the array's real number of elements, and pass the same value the caller used when declaring the array.

  • Common mistake

    Expecting the function to work on a copy

    What it looks like

    Calling double_all(values, 4) and then printing values, expecting the original numbers.

    Why it fails

    The array is not copied. The function's writes change the caller's elements.

    Do this instead

    Expect changes made through the pointer to be visible to the caller after the call returns, and use this deliberately.

Comparing With Containers That Carry Their Own Size

The contrast becomes clearer when a raw array passed as a pointer is compared with a container object. A raw array handed to a pointer parameter gives the function a location and nothing more, so the size must travel alongside it. Some container types instead keep their size together with their data, so the object itself can answer how many elements it holds. The source pack for this article does not walk through the details of any specific container type, so treat the comparison below as a conceptual contrast rather than a full lesson on those types.

FeatureArray passed to a pointer parameterContainer that stores its own size
What the function receivesA pointer to the first elementThe container object, holding its data together
Length informationNot carried by the pointer; must be passed separatelyStored with the data
Access to caller's elementsYes, through the pointer; writes are visible to the callerDepends on how the container is passed; this source pack does not cover it
Where the size comes fromThe programmer passes a countThe container itself

A conceptual contrast between a raw array handed to a pointer parameter and a container that stores its size with its data.

Trying the Hand-Off Yourself

EASY

Write a function scale_all that takes a pointer to int and a count, and multiplies each element by 3. Call it from main on an array {1, 2, 3, 4, 5} and print the result. Predict the output before you run the code.

Hints
  • Your parameter list should have the pointer first, then the count, mirroring double_all.
  • Inside the loop, use data[i] on the left and right side of the assignment.
  • Remember that the caller's array changes, so the printed values reflect the multiplication.

Key Takeaways

  • A C-style function with a pointer parameter can receive an array: the array name becomes a pointer to its first element, and that pointer is what the function receives.
  • The array is not copied. Through the pointer, the function works on the caller's own elements, so writes are visible after the call returns.
  • The pointer does not carry the array length, so the length must be passed as a separate argument.
  • Passing a count that does not match the real array, or omitting the count, are common mistakes that the programmer must prevent.
  • Containers that store their size with their data answer the length question themselves, while a raw pointer does not.

Related concepts

More concepts starting with U