I know in C, things are passed by value however I thought that arrays, if modified in functions (without making a copy) would have the original modified but when I run this code that does not happen. I am assuming range doesn't change len because of the scope?
Can someone explain?
static void task(int *b, int range){
b[range-1] = 200;
range = 0;
b = NULL;
}
int main (){
int a[]= {2,4,6};
int len = 3, i;
printf("len1: %d\n", len);
task(a,len);
printf("len %d\n", len);
for(i=0; i < len; i++){
printf("%d\n", a[i]);
}
return 0;
}
When using pointers, you can modify to what the pointer is pointing to, but not the pointer itself.
So, your function will modify a, effectively putting 200 in the last position, however, it will not become NULL.
Len wont be modified as well.
To modify both of them, you should do
void task(int **b, int *range) {
*(b)[*range - 1] = 200;
*range = 0;
*b = NULL;
}
And call it as
task(&b, &len);
But why would you want to modify the array if you are gonna set it to NULL later?
What happens when you declare the array int a[]= {2,4,6}; is that the values 2,4,6 will be stored in memory in three consecutive memory fields. In variable a will be stored the address to the first memory field (where the first array element was saved).
When calling task(a,len); you pass a copy of this address (call by value).
Because of this you can enter the array in the called function but can not override the actual variable a.
What happens there is that b[range-1] = 200; overrides the third element with 200. range = 0; and b = NULL; do only override the local variables, that only exist in the function. The least two instructions don't affect the variables in your main().
When returning to main() a and len have still the same values as before calling task(a,len);. But the values stored in the array are now a={2,4,200};.
Related
im new to the C language and im trying to understand the basic of memory allocation .
here I have two function that produce the exact same result, but only one of them using the malloc() function and the other one is not.
FIRST FUNCTION
int First()
{
int arr[] = {11, 13, 7, 12, 16};
int length = sizeof(arr) / sizeof(int);
// NOT using malloc
int arr2[length];
// Initialize elements to 0
for (int i=0; i < length; i++)
arr2[i] = 0;
// Print results
for (int i = 0; i < length; i++)
printf("%d ", arr2[i]);
return 0;
}
SECOND FUNCTION
int Second()
{
int arr[] = {11, 13, 7, 12, 16};
int length = sizeof(arr) / sizeof(int);
int *arr2;
// Here im using malloc to allocate memory
arr2 = malloc(sizeof *arr2 * length);
// Initialize elements to 0
for (int i=0; i < length; i++)
arr2[i] = 0;
// Print results
for (int i = 0; i < length; i++)
printf("%d ", arr2[i]);
return 1;
}
Both of this two functions will print: 0 0 0 0 0.
What are the differences between this two approaches ? I know that using malloc(or memset) to allocate memory based on a variable is the right approach , but im trying to understand why exactly ?
Thanks!
The difference is the lifetime of the objects. Basically it means when the object is valid and it can be accessed.
Generally, there are three lifetime types:
Static
The object is valid all the time
Example:
int* foo(void) {
static int A[10];
return A;
}
Array A is always valid. It can be safely returned from a function.
Automatic
The object is valid from its definition to end of the block where it was declared
Example:
void foo(void) {
int *p;
{
int A[10];
... A is valid here ...
p = &A[0]; // p points to
*p = 42; // still valid
}
// A is no longer valid
*p = 666; // UB strikes, expect everything
}
A pointers to automatic objects should never be returned from functions because they would point to non-existing objects. Any use of value of such a pointer triggers Undefined behavior.
Dynamic
The lifetime is controlled by the program. It starts with memory allocation via malloc() or similar functions. It ends when calling free() on the pointer to this object. Dynamic object can only be accessed via a pointer.
Example:
int* foo(void) {
int *p;
{
p = malloc(sizeof(int[10])); // p points to an object for 10 ints
*p = 42; // still valid
}
*p = 43; // still valid
return p; // still valid though function has returned
}
int *p = foo();
*p = 44;
free(p); // release
*p = 666; // UB strikes, expect everything
Forgetting to call free() usually leads to the memory leak.
The second function has a memory leak because the dynamically allocated array was not freed.
The first function is conditionally supported by compilers due to using a variable length array. Also if the size of the array is big then it can occur such a way that the array will not be allocated.
And the function memset allocates nothing.
One of the differences that I can come up with is the sizes of the arrays.
In your first function, if you put sizeof(arr2) at the end, you will get 20. But at your second function, when you put sizeof(arr2) you will get 8. (Size of a pointer depends on your computer. A pointer's size is 8 bytes in 64-bit mode. And 4 bytes in 32-bit mode.)
This question already has answers here:
Return a pointer that points to a local variable [duplicate]
(3 answers)
Closed 2 years ago.
I have a function that returns char* when I print it with printf("%c", *(k+i)); on the main it prints;
0' 10101001 Q -> Q
but if I print with printf(" %c", *(k+i)); there are less problem.
If I print inside the tobinary function, output comes perfect like this;
1010.011010011011101001011110001101010011111101111100111 -> 111011
What Am I doing wrong? here is the code.
char *tobinary(double num) {
int length = 62;
char bin[length];
int intpart = (int)num;
double decpart = 1000*(num - intpart);
int i = 0;
while (intpart!=0) {
if(intpart%2 == 1) bin[3-i] = '1';
else bin[3-i] = '0';
intpart /= 2;
i++;
}
bin[i++] = '.';
while (i <= length) {
decpart *= 2;
if (decpart >= 1000) {
bin[i] = '1';
decpart -= 1000;
}
else bin[i] = '0';
i++;
}
char *k = bin;
return k;
}
int main(int argc, char **argv) {
char *k = tobinary(10.413);
for(int i = 0; i <= 62; ++i) {
printf("%c", *(k+i));
if (i==56) printf(" -> ");
}
}
When you declare a local variable in a function, like this
char *tobinary(double num) {
int length = 62;
char bin[length];
/* ... */
}
it is stored in a special memory area called stack. Whenever a function func() is called, the CPU saves there some useful data such as the address of the calling function where the execution will be restored after func() returns, along with the parameters of func() and, as I wrote above, any local variable declared in it.
All this data is stacked with a LIFO criteria (Last In, First Out), so that when function returns a special pointer (stack pointer) is changed to point back to the data regarding the calling function. func()'s data is still there, but it can be overwritten whenever another function is called or other local variables are declared by caller(). Please note that it is compliant with the fact that local variables have a lifetime limited to the function in which they are declared.
That's what happen in your scenario. Since the execution goes on, your bin[] array is not guaranted to stay "safe":
int i is declared in the for-loop section
printf() is called
This is what corrupts "your" data (I used double quotes because it is not yours anymore).
Whenever you need to return data manipulated by a function, you have three options:
Declare the array outside it and pass it to the function after changing its prototype: int tobinary(char *arr, unsigned int arrsize, double num);. In this way the function can modify the data passed by the caller (changing at most arrsize characters). The return value can become an error code; something like 0 on success and -1 on failure.
Dynamically allocate the array inside your function using malloc(). In this case freeing the memory (with free()) is responsability of the caller function.
Declare the array in your function as static. This qualifier, in fact, tells the compiler that the lifetime of the variable is the whole life of the program, and a different specific memory area is used to store it instead of the stack. Be aware that in this case your function won't be thread safe anymore (different thread accessing the same memory area would lead to bizarre results).
bin is character array inside your function.
It is not static, so when you return a pointer to it, it is not guaranteed to keep the same value.
Either change it to static or return a memory you allocate and the caller will need to free that memory.
So, I have an array containing 1 value. And then I copy(assign) it to another array. But, if I change the value on the second array, the value of first array got changed too. This is my code:
#include <stdio.h>
void change(int a[]){
int *temp = a;
for(int i=0; i<2; i++){
a[i] = temp[0]*10+7;
}
//What I expect for the result is a[0] = 7, a[1] = 7 instead of a[0] = 7, a[1] = 77
}
int main(){
int num[1];
num[0] = 0;
change(num);
printf("%d", num[0]);
return 0;
}
What happen to my array?
EDIT : I want to copy the value, not the address of array
EDIT 2: I have change a little bit of my code above to make it more clear what I want.
"But, if I change the value on the second array, the value of first array got changed too"
Array is not passed as copy (arrays not passed by values) - it is a pointer pointing to an address where the first element is in memory. Therefore, you are actually modifying the values (arrays passed by reference)
Be aware ! When passing an array as a parameter :
void func(int a[])
means exactly the same as :
void func(int *a)
First, this declaration
void change(int a[]);
is equivalent with this declaration
void change(int *a);
Second (see this link for more info),
The C language is pass-by-value without exception. Passing a pointer
as a parameter does not mean pass-by-reference.
So you are passing a copy of the pointer's address (which points to the same array/address). Then you merely dereference the array's first position and assign a value to it (this really is just pointer arithmetic here).
Maybe it helps to rewrite the code in order to make the pointer arithmetic more obvious:
#include <stdio.h>
void change(int *a){
int temp[1];
*(temp+0) = *(a+0);
*(a+0) = *(temp+0) * 10 + 7;
}
int main(){
int num[1];
*(num+0) = 0;
change(num);
printf("%d", *(num+0));
return 0;
}
I am not sure how to understand the EDIT
EDIT : I want to copy the value, not the address of array
Looking at the code I fail to understand what you might want to try to achieve with this. Please clarify on this.
Having read your clarification I understand that you do not want to modify the array elements in the main function yet modifying them in the change function.
The answer is you cannot do that. The explanation is as mentioned above. I suggest you take some time to learn about pointer arithmetic and arrays in C. The K&R book is really excellent in that regard; I really recommend the book.
What you could do is copy the content of the array into another array and modify that one; e.g. in the beginning of the function or before calling the function and passing that copied array as parameter.
In c arrays are passed by reference. Meaning you are not passing the value but the adress where the elements of array are stored.
When you assign value to a[0] in a function, you are actually updating the num array.
When you use just an array's name to pass to a function, you actually create a temporary pointer to the first element of your array. So, your change() function receives as a copy of that temporary pointer the address of your num[] array in main.
The whole concept is called 'passing by reference'.
If you want to pass a copy of an array to a function in C, you may put the array into a struct and pass this struct by value, e.g.
struct s {
int a[4];
};
void change(struct s elem)
{
elem.a[0] = 1; //assigment to copy
}
If you want to make a copy of an array inside a function so that you can work on the array copy without changing the original array, the best option is to make an explicit copy of the array yourself.
The most portable way to do this is by using malloc() or calloc() to allocate memory, and then copying the contents of the original array to the new memory allocation. If you choose this path your code must be sure to free any dynamically allocated memory when it is no longer needed. The copying can be done by looping and using array index notation to access the allocated memory, or by using memcopy() to copy the contents of the original array. Another option is to use a Variable Length Array (added to C with C99, made optional in C11 and C17 but still widely supported) to avoid dynamically allocating and deallocating the memory yourself.
Here is an example program that contains two functions, work_on_copy() and work_on_copy_vla(), that each take an array, copy it, and do some work that changes the copy. A final argument provides an array index which is used to illustrate how the array copy can be used to modify the original array selectively after work has been done inside the function. If this argument is a valid array index, the value at that index is copied from the array copy to the original array.
Note that this problem could also be solved by wrapping an array in a struct, but this method has the disadvantage of requiring that the array member of that struct be the same size as the largest array that is expected, wasting memory in the general case.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void print_array(size_t arr_sz, int arr[]);
void work_on_copy(size_t arr_sz, int arr[], int index);
void work_on_copy_vla(size_t arr_sz, int arr[], int index);
int main(void)
{
int my_arr[] = { 1, 2, 3, 4 };
size_t my_arr_sz = sizeof my_arr / sizeof *my_arr;
puts("-- Do not change original array at all --");
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
work_on_copy(my_arr_sz, my_arr, -1);
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
work_on_copy_vla(my_arr_sz, my_arr, -1);
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
putchar('\n');
puts("-- Change specified index of original array after work --");
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
work_on_copy(my_arr_sz, my_arr, 1);
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
work_on_copy_vla(my_arr_sz, my_arr, 3);
printf("Array in main(): ");
print_array(my_arr_sz, my_arr);
return 0;
}
void print_array(size_t arr_sz, int arr[])
{
for (size_t i = 0; i < arr_sz; i++) {
printf("%d ", arr[i]);
}
putchar('\n');
}
void work_on_copy(size_t arr_sz, int arr[], int index)
{
/* make copy of array: could return a pointer to this allocation */
int *arr_copy = malloc(sizeof *arr_copy * arr_sz);
/* handle error if allocation fails */
if (arr_copy == NULL) {
perror("unable to allocate memory");
return;
}
memcpy(arr_copy, arr, sizeof *arr_copy * arr_sz); // or use a loop
/* do work on local copy */
for (size_t i = 0; i < arr_sz; i++) {
arr_copy[i] += 10;
}
printf("Array copy after work (malloc): ");
print_array(arr_sz, arr_copy);
/* update original array if needed */
if (index >= 0 && (size_t)index < arr_sz) {
arr[index] = arr_copy[index];
}
/* deallocate memory to avoid memory leaks */
free(arr_copy);
}
void work_on_copy_vla(size_t arr_sz, int arr[arr_sz], int index)
{
/* make local copy of array using a VLA */
int arr_copy[arr_sz];
for (size_t i = 0; i < arr_sz; i++) {
arr_copy[i] = arr[i];
}
/* do work on local copy */
for (size_t i = 0; i < arr_sz; i++) {
arr_copy[i] *= 2;
}
printf("Array copy after work (VLA): ");
print_array(arr_sz, arr_copy);
/* update original array if needed */
if (index >= 0 && (size_t)index < arr_sz) {
arr[index] = arr_copy[index];
}
}
Program output:
-- Do not change original array at all --
Array in main(): 1 2 3 4
Array copy after work (malloc): 11 12 13 14
Array in main(): 1 2 3 4
Array copy after work (VLA): 2 4 6 8
Array in main(): 1 2 3 4
-- Change specified index of original array after work --
Array in main(): 1 2 3 4
Array copy after work (malloc): 11 12 13 14
Array in main(): 1 12 3 4
Array copy after work (VLA): 2 24 6 8
Array in main(): 1 12 3 8
I have a function which creates an array, of say, size 5.
Is it possible for the function to accept a pointer (or maybe it needs a pointer to a pointer?) and then point said pointer at an array, so that when the callee then looks at the pointer, it can see all values of the array.
Something along the lines of this (except this will not work):
#define LENGTH 5
void assignArray(int *pointer)
{
int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
pointer = arr;
}
void main()
{
int *pointer;
pointer = malloc(sizeof(int) * LENGTH);
assignArray(pointer);
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer[i]);
}
C assign array without element by element copy
In C, arrays (compile-time allocated) cannot be assigned. You need to copy the elements from one array to another.
To avoid element-by-element copy, you can copy the whole array all at a time using library function.
I'm not very sure what you want to ask here, but it seems, you need to do memcpy() to achieve your goal.
If you have a secondary array arr to copy from, you can write
memcpy( pointer, arr, ( (sizeof arr[0]) * LENGTH ));
The code to do what you are describing might look like:
#define LENGTH 5
void assignArray(int **pp)
{
static int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
*pp = arr;
}
int main()
{
int *pointer;
assignArray(&pointer);
for (int i = 0 ; i < LENGTH ; i++)
printf("%d\n", pointer[i]);
}
Note that one does not simply point *pp at a non-static local variable arr. That is because int arr[] = .... would go out of scope when assignArray returns.
If you want each call to assignArray to "return" a different array then of course you will have to allocate space and use memcpy each time you want to make a copy of the original array.
int arr[LENGTH] = {0,1,2,3,4}; will be stack allocated, so attempting to return the pointer to any of its elements will give you undefined behaviour as the whole thing will be out of scope when the function returns.
If you want to change what a pointer is pointing to then use 2 levels of indirection ** (i.e. pass a pointer to a pointer). You'll need to allocate the array arr on the heap using malloc or something similar.
As you are trying to do it, it is not possible due to the fact that your local arr is saved to the stack and is cleaned up after the function assignArry finished. As already mentioned you need to memcpy.
This answer will have two parts:
As mentioned in other answers, this is now how you're supposed to do it. A common construct in similar code is:
void assignArray(int *dest, size_t size)
{
int i;
// initialize with some data
for (i=0; i<size; i++)
dest[i] = i;
}
This way you're not wasting space and time with an intermediate buffer.
Second part of this answer is about wrapping arrays in a struct. It's a silly trick, that in a way achieves exactly what you asked, and also something that you probably don't want because of extra data copying.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct foo { int arr[LENGTH]; };
struct foo assignArray()
{
struct foo bar = { .arr = {0,1,2,3,4} };
/* return the array wrapper in struct on stack */
return bar;
}
int main()
{
struct foo *pointer;
pointer = malloc(sizeof(*pointer));
*pointer = assignArray(); /* this will copy the data, not adjust pointer location */
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer->arr[i]);
return 0;
}
I want to use only studio.h library to convert from decimal number to binary number by using an array to store remainder but the result is not correct, maybe i have problem with memory allocation or return value is wrong, please help me to check it.
Thank you so much!
#include <stdio.h>
int n = 0;
int* DecimalToBinary(int number){
int a[10];
while(number!=0){
a[n++] = number%2;
number/=2;
}
return a;
}
void main(){
int *d1 = DecimalToBinary(5);
int *d2 = DecimalToBinary(10);
for(int i = n-1 ;i>=0;i--)
printf(" %d",d1[i]);
printf("\n");
for(int i = n-1 ;i>=0;i--)
printf(" %d",d2[i]);
}
You return a pointer to a local array. That local array is on the stack, and when the function returns the array goes out of scope and that stack memory will be reused when you call the next function. This means that the pointer will now point to some other data, and not the original array.
There are two solutions to this:
Declare the array in the function calling DecimalToBinary and pass it as an argument.
Create the array dynamically on the heap (e.g. with malloc) and return that pointer.
The problem with method 2 is that it might create a memory leak if you don't free the returned pointer.
As noted by Craig there is a third solution, to make the array static inside the function. However in this case it brings other and bigger problems than the two solutions I originally listed, and that's why I didn't list it.
There is also another serious problem with the code, as noted by Uchia Itachi, and that is that the array is indexed by a global variable. If the DecimalToBinary function is called with a too big number, or to many times, this global index variable will be to big for the array and will be out of bounds for the array.
Both the problem with dereferencing a pointer to an out-of-scope array and the indexing out of bounds leads to undefined behavior. Undefined behavior will, if you're lucky, just lead to the wrong result being printed. If you're unlucky it will cause the program to crash.
You are returning a pointer to a locally allocated array. It is allocated on the stack, and goes away when the function returns, leaving your pointer pointing to garbage.
You have a few options. You could pass an array in to fill:
void DecimalToBinary(int result[10],int number){
while(number!=0){
result[n++] = number%2;
number/=2;
}
return result;
}
// usage example:
int b[10];
DecimalToBinary(b, 42);
Or you could allocate an array on the heap:
int* DecimalToBinary(int number){
int *a = (int *)malloc(sizeof(int) * 10);
while(number!=0){
a[n++] = number%2;
number/=2;
}
return a;
}
// usage example
int *b = DecimalToBinary(42);
free(b); // when finished with it
Or you could wrap the array in a struct:
typedef struct {
int b[10];
} result;
result DecimalToBinary(int number){
result r;
while(number!=0){
r.b[n++] = number%2;
number/=2;
}
return r;
}
// usage example
result r = DecimalToBinary(42);
If you do the malloc() option, do not forget to free() the returned data when you're done with it, otherwise it will hang around. This is called a memory leak. In more complex programs, it can lead to serious issues.
Note: By the way, if your number is larger than 1023 (10 binary digits), you'll overrun the array. You may also wish to explicitly stop once you've stored 10 digits, or pass the size of the array in, or compute the required size first and allocate that much space. Also, you will get some odd results if your number is negative, you might want to use number&1 instead of number%2.
Note 2: As noted elsewhere, you should make n local, or at the very least reinitalize it to 0 each time the function is called, otherwise it will just accumulate and eventually you'll go past the end of the array.
int[10] is not the same as int *; not only is the former created on the stack, it is a different type alltogether. You need to create an actual int * like so:
int *a = malloc (10 * sizeof (int));
Of course, don't forget to free() it after use!
What you can also do and what is commonly done in C is creating the array where it is called and provide a pointer to that array to the function, this way when the array is on the stack of the function that calls it and not in the function self. We also have to specify the size of the array on to that function, since the function cannot know to how many elements the pointer points to
void DecimalToBinary( int number, int* output, unsigned size ) {
/*adapt this to your liking*/
int i;
for ( i = 0; i < size && number != 0; i++) {
output[i] = number%2;
number/2;
}
}
and in you main function you would call it like this:
int array[10];
DecimalToBinary( 5, array, sizeof(array)/sizeof(array[0]));
now array has the same result as a would have had in your example.
The problem in your code lies here..
int * DecimalToBinary(int number){
int a[10];
while(number!=0){
a[n++] = number%2;
number/=2;
}
return a;
}
The array a scope is only till this function. Once this function terminates, the memory allocated for this array will be released, either u need to use dynamic memory allocation or make array a global.
This is the correct program:
#include <stdio.h>
int n = 0;
int a[10] = {0};
int* DecimalToBinary(int number){
n = 0;
while(number!=0){
a[n++] = number%2;
number = number/2;
}
return a;
}
int main(){
int *d1;
int *d2;
int i;
d1 = DecimalToBinary(5);
for(i = n-1;i>=0;i--)
printf(" %d",d1[i]);
printf("\n");
d2 = DecimalToBinary(10);
for(i = n-1;i>=0;i--)
printf(" %d",d2[i]);
printf("\n");
}