2

I have written a function that creates a data table, initializes it's elements to 0 and returns a pointer to the data table. However it doesn't work. Could someone explain it to me so I understand where my problem is. This is my code:

#include <stdio.h>

// Here I create the data table and initialize it's elements
int* tabinit(int size) {
  int tab[size];

  for (int i = 0; i < size; i++)
    tab[i] = 0;
  return tab;
}

int main() {
  int* t = tabinit(10);

  for (int i = 0; i < 10; i++)
    printf("%d ", t[i]);
  printf("\n");
  return 0;
}
  • Duplicate of [Return a pointer that points to a local variable](https://stackoverflow.com/questions/37981475/return-a-pointer-that-points-to-a-local-variable), [How to access a local variable from a different function using pointers?](https://stackoverflow.com/questions/4570366/how-to-access-a-local-variable-from-a-different-function-using-pointers) – ReAl Nov 13 '18 at 16:40
  • Explain every line??? – Fiddling Bits Nov 13 '18 at 16:42

3 Answers3

2

When a function terminates, then all its automatic variables go out of scope.

tab is an automatic variable in this case, and will go out of scope when the function terminates. Now you are returning a pointer to a local array, so when the array goes out of scope, you will find yourself with a dangling pointer.

Didn't your compiler warned you about this? I got, in GCC, this warning:

warning: function returns address of local variable [-Wreturn-local-addr]
   return tab;
          ^~~

First make sure that you really want for practicing to create the array in the function. If not, then you don't need to, you could just create in main, and then pass it to the function.

But, if you want to practice, then you need to dynamically allocate the array, if you really want it to stay alive after the function terminates. In that case, the array will free its memory, only when you tell it to (so never forget to free).

Example:

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


int* tabinit(int size) {
  int *tab = malloc(size * sizeof(int));

  for (int i = 0; i < size; i++)
    tab[i] = 0;
  return tab;
}

int main() {
  int* t = tabinit(10);

  for (int i = 0; i < 10; i++)
    printf("%d ", t[i]);
  printf("\n");

  // do NOT forget to free
  free(t);

  return 0;
}

Output:

0 0 0 0 0 0 0 0 0 0

PS: When you get more familiar with malloc(), I suggest you read this: Should I check if malloc() was successful?

klutt
  • 30,332
  • 17
  • 55
  • 95
gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • Sounds like your "malloc()" edit and my answer were validated in a range of 2 minutes, so almost simultaneously... I don't know what to do with my answer now. The only non-duplicate part is the line about the memory leak issue. – Amessihel Nov 13 '18 at 16:53
  • @Amessihel I think your answer is useful, since it's graphical enriched. :) – gsamaras Nov 13 '18 at 16:55
  • @gsamaras could you please explain me what this line does `int *tab = malloc(size * sizeof(int));` –  Nov 15 '18 at 19:26
  • @MisterTusk it dynamically allocates memory that is as big as `size * sizeof(int)` and makes `tab` point to that memory. `sizeof(int)` is a number, which may vary among different machines. For example, in yours it could be 4. – gsamaras Nov 15 '18 at 20:57
2

You should never return a pointer to a local object. After the function finishes, the local object gets deallocated and you're left with a dangling pointer (pointer that doesn't point to valid memory).

One way to do this would be to create your object in main and pass it into your function for init, like so:

void tabinit(int* tab, int size) {
  for (int i = 0; i < size; i++)
    tab[i] = 0;
}

int main() {
  int t[10];
  tabinit(t, 10);

  for (int i = 0; i < 10; i++)
    printf("%d ", t[i]);
  printf("\n");
  return 0;
}
Kon
  • 4,023
  • 4
  • 24
  • 38
  • Change `tabinit(&t, 10);` to `tabinit(t, 10);`. I liked your answer, but your last edit is wrong, so please fix it. – gsamaras Nov 13 '18 at 16:50
  • @gsamaras why can't we use &t here? –  Nov 13 '18 at 16:57
  • 1
    @MisterTusk because the parameter type is of type`int*`, and `t` is an array. It would be incompatible. I suggest you compile it out and read the warning message, it's very informing! – gsamaras Nov 13 '18 at 16:58
1

Here:

// Here I create the data table and initialize it's elements
int* tabinit(int size) {
  int tab[size]; // <------- here

  for (int i = 0; i < size; i++)
    tab[i] = 0;
  return tab;    // <------- also here
}

As gsamaras said, the content pointed by tab become out of scope after the function call. You can change this line:

int tab[size];

By:

int *tab;
tab = malloc(size * sizeof(int));

The content will be dynamically allocated, and then will remains after exiting from the function. However, you'll have to free it manually (free(t)) afterwards or it will be reserved until the end of the program (which could occur a memory leak).

gsamaras
  • 71,951
  • 46
  • 188
  • 305
Amessihel
  • 5,891
  • 3
  • 16
  • 40