Steven Taggart
Steven Taggart

Reputation: 25

Allocating and accessing array inside C function

I have written a function to allocate memory for an array and store the array length in a pointer so I can use both in my main function. Everything seems to work fine until I try to loop through the array printing the values.

When I use the array size pointer to terminate the print loop it shows strange behaviour. Could you please show me where I am going wrong?

Thanks in advance :)

#include <stdio.h>
#include <stdlib.h>

void func (int** arr, int** len){

    int length = 5;
    *len=&length;

    *arr = malloc(sizeof(int)*(**len));

    for (int i=0; i<(**len); ++i){
        (*arr)[i]=i*10;
    }    
}

int main(){

    int* len = NULL;
    int* arr = NULL;

    func(&arr, &len);

    for (int i=0; i<5; ++i){
        printf("%d\n", arr[i]);
    } //works
    /*
    for (int i=0; i<*len; ++i){
        printf("%d\n", arr[i]);
    } //doesnt work
    */

    free(arr);

    return 0;
}

Upvotes: 1

Views: 73

Answers (3)

Madagascar
Madagascar

Reputation: 7345

for (int i=0; i<*len; ++i){
        printf("%d\n", arr[i]);
}

The above code doesn't work because the contents of len are indeterminate.

Using * with an indeterminate or NULL pointer has undefined behaviour.*

  • If an object is referred to outside of its lifetime, the behavior is undefined. The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.¹

In the function func, lenght is a local variable, which is destroyed once the function returns.

  • The lifetime of an object is the portion of program execution during which storage is guaranteed to be reserved for it. An object exists, has a constant address, and retains its last-stored value throughout its lifetime.²

  • For such an object that does not have a variable length array type, its lifetime extends from entry into the block with which it is associated until execution of that block ends in any way.³

As the lenght is known at compile time and never changes, there's no need to pass a pointer to pointer to an int. Just pass an int for the allocation.

[1], [2], [3] — C11, 6.2.4 Storage Duration of Objects.

Upvotes: 1

Ted Lyngmo
Ted Lyngmo

Reputation: 118097

int length = 5;
*len=&length;

You here assign *len to point at a local variable (length). The local variable length will go out of scope when the function returns and dereferencing the pointer after that will have undefined behavior.

You'd get the correct behavior if you instead allocate the memory for the int in main and provide a pointer to that memory to func.

#include <stdio.h>
#include <stdlib.h>

void func(int** arr, int* len) { // int* instead
    int length = 5;
    *len = length;

    *arr = malloc(length * sizeof **arr);

    for (int i = 0; i < length; ++i) {
        (*arr)[i] = i * 10;
    }
}

int main() {
    int len;               // automatic storage
    int* arr = NULL;

    func(&arr, &len);

    for (int i = 0; i < len; ++i) {
        printf("%d\n", arr[i]);
    }  // now works

    free(arr);
}

Upvotes: 1

Penguin
Penguin

Reputation: 121

You should have worked correctly with the pointer. You passed a pointer to a pointer to a function and you're trying to write a value to the pointer.

int a = 0;
fun(&a);
{
*a = 42;
}
#include <stdio.h>
#include <stdlib.h>

void func (int** arr, int* len){

    int length = 5;
    *len=length;

    *arr = malloc(sizeof(int)*(*len));

    for (int i=0; i<(*len); ++i)
    {
        (*arr)[i]=i*10;
    }    
}

int main(){

    int len = 0;
    int* arr = NULL;

    func(&arr, &len);

    for (int i=0; i<5; ++i){
        printf("%d\n", arr[i]);
    } //works
    
    for (int i=0; i<len; ++i){
        printf("%d\n", arr[i]);
    } //doesnt work
    

    free(arr);

    return 0;
}

Upvotes: 0

Related Questions