Retrieve values from arrays in different functions - c

I'm trying to write a program in c where the length of an array is declared in the main function, then a function is called and allocates the memory and initalizes the values, and then the main function prints the values. I have declared the array and its length globally, but when the main function "retrieves" values from the array, I get a segfault, which, I assume, is because only the pointer on the array is global, but not the values themselves. Is there any method of solving this besides merging the functions?

I'm trying to write a program in c where the length of an array is declared in the main function, then a function is called and allocates the memory and initalizes the values, and then the main function prints the values.
#include <stdio.h>
#include <stdlib.h>
int *foo(size_t len) {
int *values = calloc(len, sizeof *values);
if (values) {
values[2] = 42;
}
return values;
}
int main(void) {
size_t len = 5; // length of array declared in main()
int *p = foo(len); // foo() allocates and initializes
for (int k = 0; k < len; k++) printf("%d: %d\n", k, p[k]); // main() prints the values
free(p);
return 0;
}
I have declared the array and its length globally, but when the main function "retrieves" values from the array, I get a segfault, which, I assume, is because only the pointer on the array is global, but not the values themselves.
Try to avoid globals.
Do not confuse arrays and pointers. See section 6 of the c-faq.
Is there any method of solving this besides merging the functions?
Yes.

Related

C Returning an array from a function

And having some trouble grasping arrays in C and how to return them via a function. If I do something like this
int main()
{
int num_set[10]={0,1}; //initialize first two elements as 0,1 and rest as 0
int* p=num_set; //assign array to int pointer called p
printf("\n%i",&num_set); //outputs 2686660 on my machine
printf("\n%i",&num_set[0]); //also outputs 2686660
printf("\n%i",p); //also outputs 2686660
printf("\n%i",p[1]);* //outputs 0; the same as num_set[1]
}
It works as expected, but when I try to return an array through another function like the following
int multiply_by_2(int given_number)
{
int num_set[10];
for(int fun_counter=0; fun_counter<10; fun_counter++)
{
num_set[fun_counter] = (given_number*2) ;
}
return num_set; //return int array num_set to caller
}
int main()
{
int* p = multiply_by_2(300) //assign array returned by function to p
for(int main_counter=0; main_counter>10; main_counter++)
{
printf("\np[%i] = %i"
, i, p[i]);
}
}
I get an error saying "invalid conversion from 'int' to 'int*'"
They was no error when I assigned the array to an int pointer in the first code, but I get this error when I try to return it through a function.
Please help.
In C you cannot return array by value. You would have to return the pointer of the array you want to return.
Pass a pointer and a size for a buffer to store your results.
There are a number of errors here.
The return type of the function multiply_by_2 needs to be int* - i.e a pointer to an integer. What is actually returned is a pointer to the first element of the array.
You are attempting to return a variable initialized on the stack (num_set). This will
disappear as soon as the multiply_by_two function exits, because it is an automatic variable. Instead, you should use the malloc function to allocate heap memory. Here's a link explaining the difference between stack and heap memory
You have a > where you should have a < in the for loop in main. As written the loop will immediately exit.
Minor point - the number 10 is repeated several times throughout the code. It is better practice to use a variable or a #define to give the number a meaningful name
Here's an amended version of the code:
#include <stdio.h>
#include <stdlib.h> //This is required to use malloc
#define ARRAY_SIZE 10
int* multiply_by_2(int given_number)
{
int *num_set =malloc(sizeof(int)*ARRAY_SIZE);
for(int fun_counter=0; fun_counter<ARRAY_SIZE; fun_counter++)
{
num_set[fun_counter] = (given_number*2) ;
}
return num_set; //return int array num_set to caller
}
int main()
{
int* p = multiply_by_2(300); //assign array returned by function to p
for(int i=0; i<ARRAY_SIZE; i++)
{
printf("\np[%i] = %i", i, p[i]);
}
free(p);
}
This is wrong on so many levels, but the compiler error comes from your declaration of "multiply_by_2". You declare it to return an integer, but then you try to return a pointer.
Let's try something like this:
int* multiply_by_2(int size, int given_number)
{
int *ip = (int*)malloc(size*sizeof(int)); // dynamically create int x[size]
for(int fun_counter=0; fun_counter < size; fun_counter++)
{
ip[fun_counter] = (given_number*2) ;
}
return ip; //return int array num_set to caller
}
Caller must free() returned memory.
int main(int argc, char **argv) {
int *ip = multiply_by_2(3, 2);
// ip points to array {4, 4, 4}
free(ip);
return 0;
}
We say that the function caller becomes owner of returned memory, that's why you are responsible to call free() later.
int multiply_by_2(int given_number) // not returning an array, but just an int
The return type of your function is int therefore you will get an error when trying to assign it to int *. Change it to the following:
int* multiply_by_2(int given_number)
This change is acceptable because in C, an array of ints is interchangeable with a pointer to an int.
Your header is wrong. Should be
int* multiply_by_2(int given_number)
You need to return pointer of int, not just int.
Another thing, in the function multiply_by_2 you have created local array. That means that the array will be deleted after the function will end.
You must use dynamic allocation (malloc and free).
Three major problems in your program:
The return type of function is int but you are returning an int * type.
You are returning the pointer to an automatic local variable.
Second expression in for loop in main would not let the body of loop to execute.
Change return type of the function to int * and use dynamic allocation.
int* multiply_by_2(int given_number)
{
int* num_set = malloc(sizeof(int)*10);
// rest of you code
}
And finally change second expression in your for loop in main to main_counter < 10. Use free in main to free the allocated memory.

What is the type of my array? [duplicate]

This question already has answers here:
Return a 2d array from a function
(10 answers)
How to return matrix (2D array) from function? (C)
(3 answers)
Closed 8 years ago.
I have the following function :
int** myfunc() {
int array[2][2];
// operation on the array
return array;
}
And the following error from the compiler :
cannot convert 'int (*)[2]' to 'int**' in return
So my question is : how can I return my array ?
So my question is : how can I return my array ?
You cannot. The array named array has function scope and goes out of scope when the function myfunc returns. This means the array no longer exists and trying to access it will invoke undefined behaviour. Also, the return type of myfunc is int **. In the return statement
return array;
the array named array is implicitly converted to a pointer to its element. int array[2][2]; defines array to be an array of 2 elements of type int[2], i.e., an array of 2 integers. Therefore, array in the return statement is implicitly converted to type int (*)[2], i.e., a pointer to an array of 2 integers. This explains the error message.
If you want to return an array from a function, you should allocate it dynamically using malloc which should later be freed in the caller after its use.
// you should change function signature to take the array size.
// and change return type to (int *) to return a pointer to the
// first element of the dynamically allocated array
int *myfunc(int len) {
int *array = malloc(len * sizeof *array);
if(array == NULL) {
printf("error in memory allocation\n");
return NULL;
// handle it
}
// operation on the array
return array;
}
Please note that an array type object is a contiguously allocated nonempty set of objects with a particular member object type, called the element type. Therefore, a 2-D array is not a new type. It's just an array type where the elements of the array are themselves arrays. This mean we have the following equivalence -
// an automatic array of 200 elements allocated on the stack
int auto_array[10][20];
// a dynamic array of 200 elements allocated on the heap
int *dynamic_array = malloc((10 * 20) * sizeof *array);
printf("%d\n", auto_array[4][8];) // prints element in the 5th row, 9th column
printf("%d\n", dynamic_array[4*10 + 8]); // prints element in the 5th row, 9th column
This only fixes the compiler error
The compiler is already giving you the correct type to return, you just need to give the type a name to return it easily:
typedef int (*myArrayPtr)[2];
myArrayPtr myFunc() {
int foo[2][2];
return foo; //Compiles, BUT DON'T USE IT (see below)
}
Alternatively, you can write the function declaration like this (but please don't, this should only be done in code that tries to win the International Obfuscated C Code Contest):
int (*myFunc())[2] {
int foo[2][2];
return foo; //Compiles, BUT DON'T USE IT (see below)
}
This approach actually works
The code above returns a pointer to a local variable, which is automatically deallocated when myFunc() returns. If the calling function uses the returned pointer in any way, anything might happen. To return a 2D array correctly, you need to malloc() it:
typedef int myArray[2];
myArray* myFunc() {
myArray* foo = malloc(2*sizeof(*foo));
foo[1][1] = 7;
return foo;
}
Note, that one of the two dimensions is encoded in the array type, while the other one is implicit in the pointer. That is why the sizeof of *foo must be multiplied by the size of the first dimension. Of course, you can also encode both dimensions in the array type, but that requires you to write an additional dereference when you access its elements:
typedef int myArray[2][2];
myArray* myFunc() {
myArray* foo = malloc(sizeof(*foo));
(*foo)[1][1] = 7;
return foo;
}
Arrays and pointers, while deceptively similar, are not the same thing in C.
You're trying to return a local variable, memory for which is allocated on the stack. The local variable will be popped off the stack as soon as your function exits, which is why most compilers give you a warning when you try to return the address of a local variable. The returned address points to a value that is gone.
What you need to do, is declare an int** & return it. You can allocate memory dynamically using malloc() present in the malloc.h header. Something like the following should work.
#include <stdio.h>
#include <malloc.h>
int** myfunc()
{
// Allocate memory so array can hold two int *
int** array = malloc(sizeof(int *) * 2);
// Allocate memory for each of the pointers that the array holds
// We want to reserve space for two integers in each slot.
array[0] = malloc(sizeof(int) * 2);
array[1] = malloc(sizeof(int) * 2);
array[0][0] = 0;
array[0][1] = 1;
array[1][0] = 2;
array[1][1] = 3;
return array;
}
int main(void)
{
int i, j;
int **x;
x = myfunc();
for (i = 0; i < 2; ++i) {
for (j = 0; j < 2; ++j) {
printf("%d", x[i][j]);
}
}
return 0;
}
Don't forget to free() the contents of the array when you're done with it.
Arrays are not first-class data types in C, you cannot return an array by copy, and returning a reference to a local variable will have undefined behaviour (and is never good).
There are three ways (at least) to do what you are attempting. The most usual (not to mention safe and efficient) is to have the caller own the array, then pass the array into the function by reference and have the function operate on the provided array:
void myFunc( int array[2][2] )
{
// operate directly on caller's array
}
The second method is to wrap the array in a struct, which is a first-class data type and can be exchanged by copy or reference. Note for large structures, exchange by copy can become expensive computationally.
typedef struct
{
int array[2][2] ;
} array_container ;
array_container myFunc()
{
array_container contained_array ;
return contained_array ;
}
Dynamically allocating the array within the function is a possibility, but leaves the question of who is responsible for freeing the memory and how and when it is safe to do so. However although I would not recommend it:
#define ARRAY_DIM1 2
#define ARRAY_DIM2 2
int** myfunc()
{
int** array = malloc( sizeof(int*) * ARRAY_DIM1 ) ;
int* array_memory = malloc( sizeof(int) * ARRAY_DIM1 * ARRAY_DIM2 ) ;
int i = 0 ;
for( i = 0; i < ARRAY_DIM1; i++ )
{
array[i] = array_memory[i * ARRAY_DIM2]
}
return array;
}

assign dynamic array in a function and send it back to the caller in C

I have been using java for long time but for some reason I need to use C (ANSI C not C++) to write a simple code. I need to pass the pointer from outside to a function, allocate some memory to the pointer and assign some values also before the function return. I have my code like
#include <stdio.h>
#include <stdlib.h>
void test(int *a)
{
int n=3;
// I have to call another function t determine the size of the array
n = estimatesize(); // n >=3
// I tried fix size n=10 also
a = (int*)malloc(n*sizeof(int));
a[0] = 1;
a[1] = 2;
a[2] = 3;
}
void main(void)
{
int *s=NULL;
test(s);
printf("%d %d %d", s[0], s[1], s[2]);
}
I don't know why the code crashes. I thought at the beginning it is estimatesize() return wrong number but even I fix n to 10, the error still there. So I cannot pass a pointer to a function for memory allocation? If so, how can I dynamically create memory inside a function and pass it out? I know it may be a safe problem in this way but I just want to know if it is possible and how to do that. Thanks.
There are two solutions to this: Either return the pointer from the function, or pass the argument by reference.
For the first one, you simply don't take any arguments, instead you return the pointer:
int *test(void)
{
int *a = malloc(...);
...
return a;
}
int main(void)
{
int *s = test();
...
}
For the second one, you need to pass the address of the pointer, in other words a pointer to the pointer, using the address-of operator &:
void test(int **a)
{
*a = malloc(sizeof(int) * 3);
for (int i = 0; i < 3; ++i)
(*a)[i] = i;
}
int main(void)
{
int *s;
test(&s);
...
}
The reason it doesn't work now, is because the pointer (s in main) is passed by copying it. So the function test have a local copy, whose scope is only in the test function. Any changes to a in the test function will be lost once the function returns. And as s is copied for the argument, that means that s in main never actually changes value, it's still NULL after the function call.

Return integer array from function

I'm trying to return an array of integers from a function, sort the numbers then pass everything back to main. I haven't allocated and freed memory in this piece of code. I was just trying to see if it would actually work. The compiler flags an error for the statement b=sort(a). It says that it is not assignable, which would make sense. The input integers are not pointers. Is there a way to declare an array of integers as pointers? such as :
int *a[5]={3,4}
#include <stdio.h>
#include <stdlib.h>
int *sort(int *input_array);
int *sort(int *input_array)
{
return input_array;
}
int main()
{
int a[5]={3,4};
int b[5];
b=sort(a);
return 0;
}
When you create an array, you cannot assign to the array itself (only to the elements). Besides, since when you pass an array, you're passing it by reference, sort() would modify the array, making it unneeded to return it.
What you're looking for is either of: sorting the original array, which would be like this:
void sort (int * array);
void sort (int * array) {
// do stuff on the array
}
int main (void) {
int a[5] = {1, 46, 52, -2, 33};
sort(a); // result is still in a
return 0;
}
Or creating a copy and sorting it, which would be like this:
#include <stdlib.h>
#include <string.h>
int * sort (int * array, unsigned size);
int * sort (int * array, unsigned size) {
int * copy = malloc(sizeof(int) * size);
memcpy(copy, array, size * sizeof(int));
// sort it somehow
return copy;
}
int main (void) {
int a[5] = {1, 46, 52, -2, 33};
int * b; // pointer because I need to assign to the pointer itself
b = sort(a, (sizeof a) / (sizeof *a)); // now result is in b, a is unchanged
// do something with b
free(b); // you have to
return 0;
}
You can't assign arrays, they're not "first class citizens" but instead behave much like pointers.
You need something like:
int a[] = { 3, 4 };
int *b;
b = sort(a, sizeof a / sizeof *a);
The sizeof expression is needed to compute the length of the array, the sort() function can't determine that from the bare pointer it gets passed.
UPDATE: The above assumes that you won't be changing the input array, but if you do then (as pointed out in a comment, thanks) the return value is of course not needed since the caller's a will have changed when the sort() call returns.
If you are passing array - a pointer of int, you don't need to return a changed array. The array that you passed will get changed.
As #unwind suggested, you should pass number of elements to the function also so that the function knows how many elements are there in the array.
You can't return an array of anything in C. You can only return a single instance of a single datatype.
That datatype can be a pointer to memory storing a sequential list of numbers (or anything else), but you lose all information about how long the result is, so you either need to know that, or you have to have another value as an output variable to tell you the length.
You can also return a custom datatype, such as a struct, that would contain both the list of data as well as the length. However, returning a large datastructure creates multiple shallow copies of the data structure, slowing down execution of your program as well as creating memory nightmares with leaks and multiple references.
Returning a pointer to a custom data structure, however, can work very well.

Pass an array to a function by value

Below is a snippet from the book C Programming Just the FAQs. Isn't this wrong as Arrays can never be passed by value?
VIII.6: How can you pass an array to a function by value?
Answer: An array can be passed to a function by value by declaring in
the called function the array name
with square brackets ([ and ])
attached to the end. When calling the
function, simply pass the address of
the array (that is, the array’s name)
to the called function. For instance,
the following program passes the array
x[] to the function named
byval_func() by value:
The int[] parameter tells the
compiler that the byval_func()
function will take one argument—an
array of integers. When the
byval_func() function is called, you
pass the address of the array to
byval_func():
byval_func(x);
Because the array is being passed by
value, an exact copy of the array is
made and placed on the stack. The
called function then receives this
copy of the array and can print it.
Because the array passed to
byval_func() is a copy of the
original array, modifying the array
within the byval_func() function has
no effect on the original array.
Because the array is being passed by value, an exact copy of the array is made and placed on the stack.
This is incorrect: the array itself is not being copied, only a copy of the pointer to its address is passed to the callee (placed on the stack). (Regardless of whether you declare the parameter as int[] or int*, it decays into a pointer.) This allows you to modify the contents of the array from within the called function. Thus, this
Because the array passed to byval_func() is a copy of the original array, modifying the array within the byval_func() function has no effect on the original array.
is plain wrong (kudos to #Jonathan Leffler for his comment below). However, reassigning the pointer inside the function will not change the pointer to the original array outside the function.
Burn that book. If you want a real C FAQ that wasn't written by a beginner programmer, use this one: http://c-faq.com/aryptr/index.html.
Syntax-wise, strictly speaking you cannot pass an array by value in C.
void func (int* x); /* this is a pointer */
void func (int x[]); /* this is a pointer */
void func (int x[10]); /* this is a pointer */
However, for the record there is a dirty trick in C that does allow you to pass an array by value in C. Don't try this at home! Because despite this trick, there is still never a reason to pass an array by value.
typedef struct
{
int my_array[10];
} Array_by_val;
void func (Array_by_val x);
Isn't this wrong as arrays can never be passed by value?
Exactly. You cannot pass an array by value in C.
I took a look at the quoted part of the book and the source of this confusion or mistake is pretty fast found.
The author did not know about that *i is equivalent to i[] when provided as a parameter to a function. The latter form was invented to explicitly illustrate the reader of the code, that i points to an array, which is a great source of confusion, as well-shown by this question.
What I think is funny, that the author of the particular part of the book or at least one of the other parts (because the book has 5 authors in total) or one of the 7 proofreaders did not mentioned at least the sentence:
"When the byval_func() function is called, you pass the address of the array to byval_func():"
With at least that, they should had noticed that there is a conflict.
Since you passing an address, it is only an address. There is nothing magically happen which turns an address into a whole new array.
But back to the question itself:
You can not pass an array as it is by value in C, as you already seem to know yourself. But you can do three (there might be more, but that is my acutal status of it) things, which might be an alternative depending on the unique case, so let´s start.
Encapsulate an array in a structure (as mentioned by other answers):
#include <stdio.h>
struct a_s {
int a[20];
};
void foo (struct a_s a)
{
size_t length = sizeof a.a / sizeof *a.a;
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a.a[i]);
}
}
int main()
{
struct a_s array;
size_t length = sizeof array.a / sizeof *array.a;
for(size_t i = 0; i < length; i++)
{
array.a[i] = 15;
}
foo(array);
}
Pass by pointer but also add a parameter for determine the size of the array. In the called function there is made a new array with that size information and assigned with the values from the array in the caller:
#include <stdio.h>
void foo (int *array, size_t length)
{
int b[length];
for(size_t i = 0; i < length; i++)
{
b[i] = array[i];
printf("%d\n",b[i]);
}
}
int main()
{
int a[10] = {0,1,2,3,4,5,6,7,8,9};
foo(a,(sizeof a / sizeof *a));
}
Avoid to define local arrays and just use one array with global scope:
#include <stdio.h>
int a[10];
size_t length = sizeof a / sizeof *a;
void foo (void)
{
for(size_t i = 0; i < length; i++)
{
printf("%d\n",a[i]);
}
}
int main()
{
for(size_t i = 0; i < length; i++)
{
a[i] = 25;
}
foo();
}
In C and C++ it is NOT possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address. In practice this has almost the same effect and it is a much faster and more efficient operation.
To be safe, you can pass the array size or put const qualifier before the pointer to make sure the callee won't change it.
Yuo can work it around by wrapping the array into the struct
#include <stdint.h>
#include <stdio.h>
struct wrap
{
int x[1000];
};
struct wrap foo(struct wrap x)
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = x.x[index] * x.x[index];
return y;
}
int main ()
{
struct wrap y;
for(int index = 0; index < 1000; index ++)
y.x[index] = rand();
y = foo(y);
for(int index = 0; index < 1000; index ++)
{
printf("%d %s", y.x[index], !(index % 30) ? "\n" : "");
}
}
#include<stdio.h>
void fun(int a[],int n);
int main()
{
int a[5]={1,2,3,4,5};
fun(a,5);
}
void fun(int a[],int n)
{
int i;
for(i=0;i<=n-1;i++)
printf("value=%d\n",a[i]);
}
By this method we can pass the array by value, but actually the array is accessing through the its base address which actually copying in the stack.

Resources