Changing array inside function in C - c

I am learning C and confused why a array created in the main wont change inside the function, i am assuming the array passed is a pointer, and changing the pointer should've change the array , right ? can someone explain what is happening in this case?
thx for the help.
int main(){
int i, length = 10;
int array[length];
for (i = 0 ; i < length ; i++)
array[i] = i * 10;
printf("Before:");
print(array, length);
change(array, length);
printf("After:");
print(array, length);
return 0;
}
// Print on console the array of int
void print(int *array,int length)
{
int i;
for(i = 0 ; i < length ; i++)
printf("%d ", array[i]);
printf("\n");
}
// Change the pointer of the array
void change(int *array,int length)
{
int *new = (int *) malloc(length * sizeof(int));
int i;
for(i = 0 ; i < length ; i++)
new[i] = 1;
array = new;
}
I expected to see the following output:
Before:0 10 20 30 40 50 60 70 80 90
After:1 1 1 1 1 1 1 1 1 1
What i get:
Before:0 10 20 30 40 50 60 70 80 90
After:0 10 20 30 40 50 60 70 80 90

In c you can't pass a variable by reference, the array variable that you assign inside the function contains initially the same address as the passed pointer, but it's a copy of it so modifying it will not alter the passed pointer.
You need to pass the address of the pointer in order to be able to alter it, like this
// Change the pointer of the array
void change(int **array, int length)
{
*array = malloc(length * sizeof(int));
if (*array == NULL)
return;
for (int i = 0 ; i < length ; i++)
(*array)[i] = 1;
}
Then in main() you cannot assign to an array, doing so through this kind of function is surely undefined behavior. The array defined in main() is allocated on the stack and you cannot assign anything to an array since they are non-writeable lvalues so you cannot make it point to a heap memory location obtained with malloc(), you need to pass a pointer like this
int *array;
change(&array, length);
free(array);
If you want the function to replace the previous array, it will have to free() the malloc()ed data (note that passing NULL to free() is well defined), so
// Change the pointer of the array
void change(int **array, int length)
{
free(*array);
*array = malloc(length * sizeof(int));
if (*array == NULL)
return;
for (int i = 0 ; i < length ; i++)
(*array)[i] = 1;
}
then in main()
int *array;
array = NULL;
change(&array, length);
change(&array, length);
change(&array, length);
change(&array, length);
free(array);
will do what you apparently want.

Ok, i will make the answer short.
Arrays are always passed by reference in C
change(array, length);
In this line, it means reference to the first element of the array variable is passed to the function.
Now the function needs a pointer to catch the reference, it can be a pointer or it can be an array. Note that the pointer or the array is local to the function.
You received it in a pointer named array. Which is definitely a pointer but it is not the same as array in main function. It is local to the change function.
You declared a new array dynamically, and assigned a pointer named new with it. And all the changes you did were to new pointer.
Everything is ok till now.
Now you assigned the new pointer to the array pointer which is local to the change function.
This is the real issue. As even though the array is in heap section, and it will remain in the memory, but the *array and *new are local pointer variables.
Also array pointer in change function is different from array pointer in main function.
The solution to this problem is
Manipulate the data of array pointer directly.
void change(int *array,int length)
{
int i;
for(i = 0 ; i < length ; i++)
array[i] = 1;
}
In this way you are directly overwriting values of array in main function. Everything else is correct.
Summerization:
array pointer in change function is local to change function.
array in main function is local to main function.
Making change function's local array pointer point to array in heap section won't change data in actual array. You changed pointer's position, Not the array's data.

Your array in main is an array. It will decay to a pointer, to produce the behavior you expect, but it is not a pointer.
int a[10];
int* p = a; // equivalent to &a[0]; create a pointer to the first element
a = p; // illegal, a is NOT a pointer.
What your code is doing is copying the address of a into a function-local variable. Modifying it will have no more difference outside than changing length.
void change(int* local_ptr, size_t length)
{
local_ptr = 0;
length = 0;
}
int main()
{
int a[10];
int length = 10;
printf("before a=%p, length=%d\n", a, length);
change(a, length); // we copied 'a' into 'local_ptr'.
printf("after a=%p, length=%d\n", a, length);
}
If you wish to modify a pointer from the caller, you will need to use pointer-to-pointer syntax:
void change(int** ptr, size_t length)
{
// change the first element:
**ptr = 0;
// change the pointer:
*ptr = 0;
// but ptr itself is a function-local variable
ptr = 0; // local effect
}
However: There is a problem with what you are trying to do that goes deeper than this.
In your code, "int a" is an array on the stack, not an allocated pointer; you cannot free it and you should avoid mixing heap/stack pointers this way because eventually you'll free the wrong thing.

A simple example:
#include <stdio.h>
void print_array(const int arr[], const int n){
int i;
for(i=0; i < n; i++)
printf("%d ", arr[i]);
printf("\n");
}
void change_array(int arr[]){
arr[0] = 239;
arr[1] = 234234;
}
int main(){
int arr[10] = {};
print_array(arr,10);
change_array(arr);
print_array(arr,10);
return 0;
}
The output:
0 0 0 0 0 0 0 0 0 0
239 234234 0 0 0 0 0 0 0 0

If you are looking for the simplest way to modify the data pointed to by 'array', rewrite the 'change' function to:
// [OLD COMMENT] Change the pointer of the array
// [NEW COMMENT] Change the value(s) of data pointed to by 'array'
void change(int *array, int length)
{
int i;
for(i = 0 ; i < length ; i++)
array[i] = 1;
}
When you pass the name of the integer array called 'array', you are passing a pointer to the array data declared in main. In the function 'change' the pointer is copied (passed by value) and it is used in the function as it would have in main. No need for malloc.

You pass a pointer to the array array to the function change. In this function you create another array called new (using new as a name is a bad idea) and then assign it to the locally created function parameter array. You do not modify pointer in your main function. If you would like to do so, you should use
array = change(array,length);
in your main function and
int *change(int *array, int length) {
int *variable_called_new =(int *)malloc(length*sizeof(int));
[...]
return variable_called_new
}
in your change function.

To use pass by value:
Make the following change:
In function change(...), replace:
int i;for(i=0;i<length;i++)new[i] = 1;
To:
int i;for(i=0;i<length;i++)array[i] = 1;
^^^^^
EDIT:
But to use pass by reference:
//To change the contents of a variable via a function call
//the address of that variable has to be passed. So, if you
//want to change the contents of an array of int, i.e. int *array, you
//need to pass its address, not the variable itself, using the
//address of operator, it would look like this &array (read _the address of
// pointer to int "array")
//This requires you to change the prototype of your function:
void change2(int **a, int len)
{
int i;
for(i=0;i<len;i++) (*a)[i] = 1;//parenthesis bind * to a to assure
//array of pointers to int ( *[] )is populated
//
}
Then in main, make the following changes, and it will work as you purposed:
int main(){
int i,length=10;
int *array;
array = calloc(length, sizeof(int));
if(!array) return 0;
//or malloc if preferred. But note, in C,
//casting the output is not required on either.
//array = malloc(length*sizeof(int));
//if(!array) return 0;
for(i=0;i<length;i++)array[i]=i*10;
printf("Before:");print(array,length);
change2(&array,length);
printf("After:");print(array,length);
free(array);
return 0;
}

so when you pass the array you get the address of it's beginning:
memory address
|-junk-| 1000
|---0---| 1008 <- start of your array
|---10--| 1012
. .
. .
when you get the pointer in your function its value is 1008(example) so changing that will only mean you now point to another place. that is not what you want.
you can change the integers pointed at directly via the * operator, so
*array = 99; will change the first element,
*(array+1) = 98; the second and so on.
you can also, more naturally use the [] operator.
so in your function
array[0] = 99; will actually change the original array.

#include<stdio.h>
#include<stdlib.h>
// Print on console the array of int
void print(int *array,int length)
{
int i;
for(i = 0 ; i < length ; i++)
printf("%d ", array[i]);
printf("\n");
}
// Change the pointer of the array
void change(int **array,int length)
{
int i;
int *ar;
ar = (int *)malloc(sizeof(int *) * length);
for(i = 0 ; i < length ; i++)
ar[i] = 1;
(*array) = ar;
}
int main(){
int i, length = 10;
int *array;
array = (int *)malloc(sizeof(int *) * length);
for (i = 0 ; i < length ; i++)
array[i] = i * 10;
printf("Before:");
print(array, length);
change(&array, length);
printf("After:");
print(array, length);
return 0;
}

You are passing your array's reference to the function change() and the rererence is getting copied to pointer array in change.
And then you're creating a variable new and assigning the memory space using malloc and following that you're assigning some values to it.
Until now your pointer array in change() is pointing to the array in main.
In the next statement you're making your array in change() point to the space pointed by the variable `new and the pointar array is not pointing to the array in the main any more.
So instead of using new[i] = 1 use array[i] = 1 in change().

Related

Can I get the size of an array returned from a function in C?

My function arrayReturn() returns the address of array a.
In main() I assign the address to a pointer p and I print the array.
Is there any way to know the size of the array from the function? Assuming we don't know the size,
it is possible, instead of for(i = 0; i < 3; i++) to write something like
for(i = 0; i < sizeof(p); i++)?
#include <stdio.h>
int * arrayReturn();
int main()
{
int *p = arrayReturn();
int i;
for(i = 0; i < 3; i++)
{
printf("%d ", *(p+i));
}
return 0;
}
int * arrayReturn()
{
static int a[] = {11, 22, 33};
return &a;
}
Pointers store the address of a single object - that object may be the first element of an array, it may be an element in the middle of an array, or it may be a single object that isn't part of an array.
There's no way to determine from the pointer value itself whether it points to an element of an array or not.
You'll have to return the array size as a separate item, either as a writable parameter or as a member of a struct type that also stores the pointer.

New beginner for dynamically allocated Array. Why do I have segmentation fault here?

I use nested data structure for fibonacci, but I have a segmentation fault 11.
void fib(int **fib_array, int n){
fib_array = malloc(n * sizeof(int*));
for(int i = 0; i < n; i++){
fib_array[i] = malloc(sizeof(int));
}
for(int i = 0; i < n; i++){
if (i <= 1){
fib_array[i][0] = i;
}
else{
fib_array[i][0] = fib_array[i - 2][0] + fib_array[i - 1][0];
}
}
}
int main(int argc, char **argv) {
/* do not change this main function */
int count = strtol(argv[1], NULL, 10);
int *fib_sequence;
fib(&fib_sequence, count);
for (int i = 0; i < count; i++) {
printf("%d ", fib_sequence[i]);
}
free(fib_sequence);
return 0;
}
you are being too complicated. You just need a single malloc
*fib_array = malloc(n * sizeof(int));
and remove you second indexings [0] from everywhere
The consfusion comes from **int. This looks like a multi dim array. Its not - its declared ** so that you can set the value in the caller. A simpler exampe will help
void Make42(int* v)
{
*v = 42;
}
int main()
{
int myv = 0;
Make42(&myv);
// now myv == 42
}
The * in the arg list is so that Make42 can 'reach out' and modify what was passed to it (myv in this case)
In your code the ** on fib array is there for the same purpose. you could have done (In know you werent allowed to by the test definition )
int *fib(int n){
int *fib_array = malloc(n * sizeof(int));
......
return fib_array;
}
and in main
fib_sequence = fib(count);
this makes it much clearer that you are really manipulating a simple array
pm100 is right, but a little short for answering to a beginner...
At first, you have passed a pointer to a pointer. If you want the original pointer to contain a value, you need to dereference the pointer to pointer:
*fib_array = ...
By assigning to the pointer only (as you did in your code), you do not modify the orignial pointer (fib_sequence in main) at all. And as you have not initialised it, it might point to anywhere, thus the segmentation fault when you try to print the values of it.
Then why an array of pointers to individually stored values? You can use a contiguous array of ints, which you get by
*fib_array = malloc(n * sizeof(int));
OK, further usage won't be too nice ((*fib_array)[i] = ...), so I recommend a temporary variable instead:
int* fa = malloc(n * sizeof(int));
// now fill in the values comfortably:
fa[i] = ...;
// finally, assign the pointer to the target:
*fib_array = fa;
Side note: always check the result of malloc, it could be NULL:
fa = ...
if(fa)
// assign values
else
// appropriate error handling
In your concrete case, you could omit the else branch in your function and check your pointer outside within main function.
By the way, a simple return value would have made your live easier, too:
int* fib(int n)
{
int* fib_array = malloc(n * sizeof(int*));
// ...
return fib_array;
}
Notice: no need for pointer to pointer... Usage:
int* fib_sequence = fib(count);

the function corrupted my array in C

Hello I'm build a function are printing array with pointers
on c with Visual Studio 2015.
while i run the function this send me this massage:
Run-Time Check Failure #2 - Stack around the variable 'arr' was corrupted.
this the function:
void arrprint(int* arr, int size)//printing numbers:
{
size = (int)arr + size*sizeof(int);// the last adress of the array
int* firstAdress = arr;
for (arr=firstAdress; arr < size; arr++)
{
printf("%2d", *arr); //printing
}
*arr = firstAdress; //for not destroy the array
printf("\n");
}
thanks for helpers
This line
*arr = firstAdress; //for not destroy the array
destroys the array. You are writing into the memory when you dereference arr.
Since in C, everything is passed by value, you do not have to worry about corruption when you change arr in the function. So, you do not need firstAdress.
void arrprint(int* arr, int size)//printing numbers:
{
int* lastAddress = arr + size;
int* firstAdress = arr;
for (arr=firstAdress; arr < size; arr++)
{
printf("%2d", *arr); //printing
}
printf("\n");
}
After Updating, the code should look like this. You should notice that arr which is being changed here, is only being changed in this function, and the actual array pointer (in the caller function) is intact and safe.
You're trying to use size as an int *. Use an actual int * instead.
Also, by setting *arr = firstAddress, what you're really doing is writing the address of the array into the first element in the array. Also, since arr is a local variable, changes to it don't affect the variable in the calling function.
void arrprint(int* arr, int size)//printing numbers:
{
int *lastAddress = arr + size;
int *firstAdress = arr;
for (arr=firstAdress; arr < lastAddress; arr++)
{
printf("%2d", *arr); //printing
}
printf("\n");
}
Personally think the best solution is:
void arrprint(int* arr, int size)//printing numbers:
{
int *lastAddress = arr + size
int *firstAddress = arr;
for (firstAddress = arr; firstaddress < lastAddress; firstaddress++)
{
printf("%2d", *firstAddress); //printing
}
printf("\n");
}
Reason you do not alter the original pointer. You can also use const int* arr in the function declaration, then you will get a compiler error if you dereference the pointer.

returning 2D array having error, need concept

I tried different methods but eventually got errors. Please give a solution and a brief explanation of the concept.
uint8_t **subBytes()
{
int i,j;
uint8_t r,c;
uint8_t t[4][4];
for(i=0;i<4;i++)
{
for (j=0;j<4;j++)
{
r = pt[p1][j] & 0xf0;
r = r >> 4;
c = pt[p1][j] & 0x0f;
t[i][j] = (uint8_t *) malloc(sizeof(uint8_t));
t[i][j] = sBox[r][c];
}
p1++;
}
return t;
}
int main()
{
uint8_t **temp;
temp = subBytes();
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
printf("%x ", temp[i][j]);
}
printf("\n");
}
}
This is my original code. Here, I used malloc, but then too it is not working.
the memory space alloced for your matrix is a LOCAL VARIABLE.
The scope of a LOCAL VARIABLE is only within that function.
When you returned it is discarded.
In your code it is uint8_t t[4][4].
t is discarded right after return t.
So you return nothing and may cause undefined behavior.
You should use malloc to alloc memory for your matrix not just declare it locally.
in code
uint8_t **t.
t = malloc(sizeof(uint8_t) * 16 ) //size of a 4x4 matrix
then use t as a two dimension array and return t.like
t[0][0] = 1;
don't forgot to free it after use it out side of the function.
free(t);
m is LOCAL VARIABLES. When add returns, m is DESTROYED!
You SHOULD NOT return the pointer or reference of local variables. Look the following code:
int foo() { return 1; }
int *bar() { int i = 1; return &i; }
When I call foo(), it returns 1.
When I call bar(), it try to return the local variables, i's address. But when bar() returns, the i variable is DESTROYED! So the return pointer become trash pointer. (Sorry, I don't know how to say that term in English;)
You should use like that:
void bar(int *ret) { *ret = 1; }
int i;
bar(&i); /* now i is 1 */
or
int *bar()
{
int *p = (int *)malloc(sizeof(int));
*p = 1;
return p;
}
int *pi = bar();
/* now *pi is 1 */
...
free(pi); /* You MUST free pi. If not, memory lack is coming~ */
(I recommend first one. the second one require free and it can be mistaken.)
When a variable is declared (statically allocated) within a function, it is placed on what is called the stack, which is only local to that function. When the program leaves that function's scope, the variable is no longer guaranteed to be preserved, and so the pointer you return to it is essentially useless.
You have three options to fix your error:
Don't do it
Simply declare the array in the same function as you use it, don't bother with trying to return a pointer from another function.
Pass a pointer to a variable local to main
A pointer to a variable local to main will be valid until main returns, so you could do this:
void subBytes(uint8_t t[4][4]){
//perform initialization of matrix on passed variable
}
int main(){
uint8_t temp[4][4];
subBytes(&temp);
//...
}
Dynamic Allocation
This will probably give you more errors than it will solve in this case, but if you are heartset on returning a pointer to a matrix, you could malloc() the memory for the array and then return it, but you would have to free() it afterwards.
In C, there are several ways to dynamically allocate a 2D array. The first is to create it as a single array, and operate on the indices to treat it as 2D.
//...
int *arr = (int *)malloc(rows*cols*sizeof(int));
for (int i = 0; i<rows; i++){
for (int j = 0; j<height; j++){
arr[i*height + j] = i*j; //whatever
}
}
return arr; // type is int *
//...
Note that in this method, you cannot use array[i][j] syntax, because the compiler doesn't know the width and height.
The second way is to treat it as an array of arrays, so store an array of pointers to other arrays.
//...
int **arr = (int **)malloc(rows*sizeof(int *));
for (int i = 0; i<rows; i++){
arr[i] = (int *)malloc(cols*sizeof(int));
}
arr[i][j] = 86; //whatever
return arr; //type is int **
//...
For further information, see: Pointer to Local Variable

Function with return type array in C

I have the following function in C:
int[] function(int a){
int * var = (int*)malloc(sizeof(int)*tags);
....
}
*var is it a pointer to an array var?
If yes, how can I return the array (var) in the function?
You can't really return an array from a function, but a pointer:
int * function(int a){
int * var = malloc(sizeof(int)*tags);
//....
return var;
}
This code below could clarify a bit how array and pointers works.
The function will allocate memory for "tags" int variables, then it will initialize each element with a number and return the memory segment that points to the array.
From the main function we will cycle and print the array element, then we will free the no longer needed memory.
#include <stdio.h>
#include <stdlib.h>
int *function(unsigned int tags) {
int i;
int *var = malloc(sizeof(int)*tags);
for (i=0; i < tags; i++) {
var[i] = i;
}
return var;
}
int main() {
int *x;
int i;
x = function(10);
for (i=0; i < 10; i++) {
printf("TEST: %i\n", x[i]);
}
free(x); x=NULL;
return 0;
}
How about:
int* function(int tags){
int * var = malloc(sizeof(int)*tags);
//....
return var;
}
Arrays and pointers to the base element type are (mostly) synonymous in C/C++, so you can return a pointer to the first element of an array and use that as if it was the array itself.
Note, your code has an input parameter a, but using tags to allocate the memory for the array. I assumed in the above code that you wanted to use the input parameter for that purpose
Also, you will have to call free() on the pointer returned by function above, when you are no longer using the array, to avoid memory leaks. malloc above allocates memory enough to hold tags number of ints, so the array is equivalent to int var[tags];
UPDATE: removed cast for malloc's return
In C, functions cannot return array types. For your purposes, you want to return a pointer to int:
int *function(int a)
{
int *var = malloc(sizeof *var * tags); // where is tags defined?
// are you sure you don't mean a here?
...
return var;
}
This will allocate a block of memory large enough to hold tags integer values and assign the address of the first element of that block to var. Note that var is a pointer to int, not a pointer to an array of int. That pointer is what gets returned from the function.
You can use the subscript oprerator on a pointer expression as though it were an array, like so:
int a = ...;
int *arr = function(a);
...
arr[0] = 0;
arr[1] = 1;
...
arr is a pointer expression, not an array expression, so sizeof arr will return the size of the pointer type, not the size of the block of memory that it points to (because of this, you will want to keep track of the number of elements you allocated separately).
In C an array is basically the same type as a pointer to an element of the array.
So char[] is basically char*
Don't forget to keep track of the size of the array, also I noticed that tags seems to be a global variable, most of the time it's a good idea to avoid global variables
Here is some example code:
#include <stdio.h>
#include <stdlib.h>
int* foo(size_t arrSize){
int* arr = (int*) malloc(sizeof(int)*arrSize);
return arr;
}
int main (int argc, char** argv){
printf("Printing array:\n");
int* arr = foo(42);
for(int i=0; i <42; i++){
arr[i]=i;
}
for (int i=0; i < 42; i++){
printf("Element: %d: %d\n", i, arr[i]);
}
free(arr);
return 0;
}

Resources