Returning a pointer to an array - c

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;
}

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?

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;
}

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).

Related

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;
}
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);
}
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.
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;
}

Dynamic allocation example in C

What is going on with adress and pointer types.
Can we dealocate the momory in the main function.
int *read(int *n) {
int i, *niz;
do {
printf("n=");
scanf("%d", n);
} while (*n < 1);
niz = (int *)malloc(*n * sizeof(int));
for (i = 0; i < *n; i++) {
printf("%d. broj: ", i + 1);
scanf("%d", niz + i);
}
return niz;
}
int main() {
int i, n, *niz;
niz = read(&n);
printf("Niz:");
for (i = 0; i < n; i++)
printf(" %d", niz[i]);
free(niz);
return 0;
}
I don't understand why do we need a function pointer (*read), and why
do we need the pointer in the read function while using n?
To make it clear you may rewrite the function declaration
int *read(int *n) {
the following way
int * ( read(int *n) ){
That is it is a function that has one parameter with the name n of the type int * and the return type int *.
In main the variable n declared like
int i, n, *niz;
is passed to the function read by reference through a pointer to it
niz = read(&n);
because we want that the variable would get a value assigned in the function. So dereferencing the pointer the function will have a direct access to the original variable n declared in main and can change its value.
This value assigned in the function read to the original variable n declared in main through a pointer to it is used in main in this for loop
for (i = 0; i < n; i++)
printf(" %d", niz[i]);
Otherwise if the function would be declared like
int * ( read(int n) ){
and called like
niz = read(n);
then the function would deal with a copy of the value of the variable n declared in main. Changing the copy of the value of the variable n within the function leaves the value of the original variable n declared in main unchanged. It is the copy of the value that would be changed not the original variable itself.
Pay attention to that the returned pointer from the function points to a dynamically allocated memory. So using the pointer in main you can free the allocated memory within the function.

In C - Can I initialize an array (and set the size) from within a function?

I am trying to pass a pointer to a funcion, and in that function create an array, and set the passed pointer to that array.
What I'm trying to do is create an array inside the function and then use that array outside the funcion.
void createArray(int *myPointer)
{
int intArray[20];
*myPointer = &intArray[0]; // This line gets error:
// assignment makes integer from pointer without a cast [-Wint-conversion]
for (int i = 0; i < 20; i++)
{
intArray[i] = i + 10;
}
}
int main(void)
{
int *intPointer;
createArray(&intPointer);
for (int i = 0; i < 20; i++)
{
printf("%d : %d \n", i, intPointer[i]);
}
return 0;
}
You meant to use
void createArray(int **myPointer)
That will resolve the two type errors.
But that will make main's pointer point to a variable that no longer exists after createArray returns. That's bad. And that's why you have to use malloc instead of automatic storage.
void createArray( int **myPointer ) {
int *intArray = malloc( 20 * sizeof(int) );
*myPointer = intArray; // Same as `&intArray[0]`
if ( !intArray )
return;
for ( int i = 0; i < 20; i++ )
intArray[i] = i + 10;
}
int main(void) {
int *intPointer;
createArray(&intPointer);
if ( intPointer ) {
perror( NULL );
exit( 1 );
}
for (int i = 0; i < 20; i++)
printf( "%d: %d\n", i, intPointer[i] );
return 0;
}
The reason for the compiler error is the *myPointer dereferencing, which gives you the content of type int that the pointer points at. The compiler is saying that you can't assign the pointer &intArray[0] to a plain int.
Besides being invalid C, it wouldn't change where the pointer points. To do that, you would have to do myPointer = &intArray[0];. However, in this case you can't do that either because the myPointer is just a local pointer variable inside the function - a local copy of the pointer you passed. You need a way to update the pointer in main().
Furthermore, we can never return a pointer to local data (data with "automatic storage duration") because that data ceases to be valid as soon as we leave the function.
The normal solution is to create dynamically allocated memory instead, since such memory persists throughout the execution of the program (or until you explicitly free it). There are two different ways to write a function for that:
#include <stdlib.h> // for malloc
int* createArray (void)
{
int* result = malloc(20 * sizeof(*result));
if(result == NULL)
return NULL; // some error handling will be required here
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
return result;
}
...
int *intPointer = createArray();
...
free(intPointer);
Alternatively you could pass the pointer itself by value, so that by doing the *myPointer = ...; assignment, you refer to where a int** points at:
#include <stdlib.h> // for malloc
void createArray (int** myPointer)
{
int* result;
result = malloc(20 * sizeof(*result));
if(result == NULL)
{
/* some error handling will be required here */
}
for (int i = 0; i < 20; i++)
{
result[i] = i + 10;
}
*myPointer = result;
}
...
int *intPointer;
createArray(&intPointer);
...
free(intPointer);
Either of these are ok and which one you use is mostly a matter of design. It's easier syntax to have the pointer returned, but then normally the return of functions is reserved for some error code.

Pass char** as an argument to a function in C

I know there are many topics of this kind but I've read several of them and still can't figure out what am I doing wrong.
I've successfully generated a char** array. My bubble sort function probably works as well. But when I passed the generated array to the function, only 1 row is copied.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
void sort(char** tab)
{
char* temp;
int i, j, size = sizeof(tab)/sizeof(tab[0]);
printf("%d\n", size);
for(i = 0; i < size; ++i)
{
for(j = i+1; j < size; ++j)
{
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
}
}
for(i = 0; i < sizeof(tab)/sizeof(tab[0]); ++i)
puts(tab[i]);
}
int main()
{
srand(time(NULL));
int size = rand()%5+5, i, j, s;
char** tab = (char**)malloc(size * sizeof(char*));
for(i = 0; i < size; ++i)
{
s = rand()%9+1;
tab[i] = (char*)malloc(s+1);
for(j = 0; j < s; ++j)
tab[i][j] = 'a'+rand()%26;
tab[i][s] = 0;
}
for(i = 0; i < size; ++i)
puts(tab[i]);
puts("");
sort(tab);
return 0;
}
Here's how the code works.
And when I write size=5 before the loop in the function it returns segmentation fault.
Edit: Same with passing the size of the array as an argument:
http://ideone.com/3Wvncq
Final code
I've fixed all the problems and here's the final code.
I was misinterpreting segmentation fault as the result of assigning a fixed size instead of not allocating the temp variable.
Thank you for all the answers.
Don't calculate size inside function void sort(char** tab) . As in this function it will be calculated as -
int i, j, size = sizeof(tab)/sizeof(tab[0]); // equivalent to sizeof(char **)/sizeof(char*) in function giving wrong length as you desire.
It's length in main(size is generated using rand so no need to find it) and then pass it as argument to function sort.
Declare your function like this -
void sort(char** tab,size_t size)
And while calling from main pass length of tab to it -
sort(tab,size); // size will be number of elements in tab calculated in main
You get segmentation fault because of this -
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
temp is uninitialized in sort and still you pass it to strcpy thus undefined behaviour . Initialize temp before passing to strcpy.Allocate memory to temp in function sort.
In your sort function you declare the temp variable:
char* temp;
Later you use it as destination (and source) for string copying:
strcpy(temp, tab[j-1]),
But nowhere in between do you make temp point anywhere, temp is uninitialized and that leads to undefined behavior and your crash.
Don't use a pointer, instead declare it as an array of the largest string size possible.

How to return an array from a function with pointers

i'm trying to figure out how to return an array from a function in the main().
I'm using C language.
Here is my code.
#include <stdio.h>
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
main(){
int i, n = 5;
int *array[n];
array[n] = initArray(n);
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
printf("\n\n");
}
And this is the errors the console gives me:
2.c: In function ‘initArray’:
2.c:8:13: warning: assignment makes pointer from integer without a cast [enabled by default]
array[i] = i*2;
^
2.c:11:3: warning: return from incompatible pointer type [enabled by default]
return array;
^
2.c:11:3: warning: function returns address of local variable [-Wreturn-local-addr]
2.c: In function ‘main’:
2.c:23:4: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("%d ", array[i]);
^
It's impossible!
I hate being a noob :(
If you could help, with explanations, I would appreciate! :D
Edit: iharob's answer is better than mine. Check his answer first.
Edit #2: I'm going to try to explain why your code is wrong
Consider the 2nd line of main() in your question:
int *array[n];
Let's try to read it backwards.
[n]
says we have an array that contains n elements. We don't know what type those elements are and what the name of the array is, but we know we have an array of size n.
array[n]
says your array is called array.
* array[n]
says you have a pointer to an array. The array that is being pointed to is called 'array' and has a size of n.
int * array[n];
says you have a pointer to an integer array called 'array' of size n.
At this point, you're 3/4 way to making a 2d array, since 2d arrays consist of a list of pointers to arrays. You don't want that.
Instead, what you need is:
int * array;
At this point, we need to examine your function, initArray:
int *initArray(int n){
int i;
int *array[n];
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
The second line of initArray has the same mistake as the second line of main. Make it
int * array;
Now, here comes the part that's harder to explain.
int * array;
doesn't allocate space for an array. At this point, it's a humble pointer. So, how do we allocate space for an array? We use malloc()
int * array = malloc(sizeof(int));
allocates space for only one integer value. At this point, it's more a variable than an array:
[0]
int * array = malloc(sizeof(int) * n);
allocates space for n integer variables, making it an array:
e.g. n = 5:
[0][0][0][0][0]
Note:The values in the real array are probably garbage values, because malloc doesn't zero out the memory, unlike calloc. The 0s are there for simplicity.
However, malloc doesnt always work, which is why you need to check it's return value:
(malloc will make array = NULL if it isn't successful)
if (array == NULL)
return NULL;
You then need to check the value of initArray.
#include <stdio.h>
#include <stdlib.h>
int *initArray(int n){
int i;
int *array = malloc(sizeof(int) * n);
if (array == NULL)
return NULL;
for(i = 0; i < n; i++){
array[i] = i*2;
}
return array;
}
int main(){
int i, n = 5;
int *array = initArray(n);
if (array == NULL)
return 1;
printf("Here is the array: ");
for(i = 0; i < n; i++){
printf("%d ", array[i]);
}
free(array);
printf("\n\n");
return 0;
}
You can't just return an array like that. You need to make a dynamically allocated array in order to do that. Also, why did you use a 2d array anyway?
int array[5];
is basically (not completely) the same as:
int * array = malloc(sizeof(int) * 5);
The latter is a bit more flexible in that you can resize the memory that was allocated with malloc and you can return pointers from functions, like what the code I posted does.
Beware, though, because dynamic memory allocation is something you don't wanna get into if you're not ready for tons of pain and debugging :)
Also, free() anything that has been malloc'd after you're done using it and you should always check the return value for malloc() before using a pointer that has been allocated with it.
Thanks to iharob for reminding me to include this in the answer
Do you want to initialize the array? You can try it like this.
#include <stdio.h>
void initArray(int *p,int n)
{
int i;
for(i = 0; i < n; i++)
{
*(p+i) = i*2;
}
}
void main(void)
{
int i, n = 5;
int array[n];
initArray(array,n);
printf("Here is the array: ");
for(i = 0; i < n; i++)
{
printf("%d ", array[i]);
}
printf("\n\n");
}
If you don't want to get in trouble learning malloc and dynamic memory allocation you can try this
#include <stdio.h>
void initArray(int n, int array[n]) {
int i;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
}
int main() { /* main should return int */
int i, n = 5;
int array[n];
initArray(n, array);
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
printf("\n\n");
return 0;
}
as you see, you don't need to return the array, if you declare it in main(), and pass it to the function you can just modify the values directly in the function.
If you want to use pointers, then
#include <stdio.h>
int *initArray(int n) {
int i;
int *array;
array = malloc(n * sizeof(*array));
if (array == NULL) /* you should always check malloc success */
return NULL;
for (i = 0 ; i < n ; i++) {
array[i] = i * 2;
}
return array;
}
int main() { /* main should return int */
int i, n = 5;
int *array;
array = initArray(n);
if (array == NULL) /* if null is returned, you can't dereference the pointer */
return -1;
printf("Here is the array: ");
for(i = 0 ; i < n ; i++) {
printf("%d ", array[i]);
}
free(array); /* you sould free the malloced pointer or you will have a memory leak */
printf("\n\n");
return 0;
}

Resources