Arrays getting passed through a function - c

I am learning how variables are passed to functions by value, while arrays are passed by reference.
I ran my script to verify that, however the pointer addresses are different. Why is that?
void arrayFunction(int array[4]);
int main(void){
int foo[4] = {0, 1, 2, 3};
printf("This is the address to foo in main: %p\n",&foo);
arrayFunction(foo);
}
void arrayFunction(int array[4]){
printf("This is the address to array in method: %p\n", &array);
array[0] = 22;
}

The is the address of foo aka &foo[0] is conceptually copied to a new variable. Or said differently the pointer is still passed by value.

&array is the address of the array variable in the stack of the called function. However that's implemented as a pointer that points to the same array elements.
Here is a modified version of your program showing that:
#include <stdio.h>
void arrayFunction(int array[4]);
int main(void){
int foo[4] = {0, 1, 2, 3};
printf("This is the address to foo in main: \t%p\n",&foo[0]);
arrayFunction(foo);
}
void arrayFunction(int array[4]){
printf("This is the address to array in method: \t%p\n", &array[0]);
array[0] = 22;
}

There is a subtle difference between the array and the normal element. If arr[10] is declared, then only (arr) gives the address of the first emement.
In your code, you have print address of the pointer pointing to that first element '&arr'. Just remove the '&' and both will show the same address.
#include<stdio.h>
void arrayFunction(int array[4]);
int main(void){
int foo[4] = {0, 1, 2, 3};
printf("This is the address to foo in main: %p\n",foo);
arrayFunction(foo);
}
void arrayFunction(int array[4]){
printf("This is the address to array in method: %p\n",array);
array[0] = 22;
}

Related

Function that returns an array used multiple times gives same value every time

I want to make a function that returns an int array. However I am having difficulties as this attempt will return the same value for both out1 and out2
int * foo(int bar) {
static int fizz[2] = {0, 0};
fizz[0] = bar;
fizz[1] = bar + 1;
return fizz;
}
int main() {
int *out1 = foo(1);
int *out2 = foo(2);
printf("(%d, %d)\n(%d, %d)", out1[0], out1[1], out2[0], out2[1]);
}
Output:
(2, 3)
(2, 3)
And then this solution does not compile as I am returning the address of a local variable (which is what lead me to attempt the static keyword in the first place.
int * foo(int bar) {
int fizz[2] = malloc(2*sizeof(int));
fizz[0] = bar;
fizz[1] = bar + 1;
return fizz;
}
int main() {
int *out1 = foo(1);
int *out2 = foo(2);
printf("(%d, %d)\n(%d, %d)", out1[0], out1[1], out2[0], out2[1]);
}
So I know why this code is not working but I have no clue what other methods I could attempt to successfully write this function.
Your second attempt is close, and certainly along the right path. However, the return value from the malloc function is a pointer (not an array) and the fizz variable should be declared as such (a pointer-to-integer, or int*).
Your concern about this "returning the address of a local variable" is not relevant, in this case; what you are returning is the value of a local variable, which just happens to be an address. The value of that address, returned by malloc, will be copied to the value returned by the function.
Also, when using malloc , never forget to release the memory when you're finished with it, using the free function.
Here's a working code sample, which is changed very little from your second snippet:
#include <stdio.h>
#include <stdlib.h>
int* foo(int bar)
{
int *fizz = malloc(2 * sizeof(int)); // Save the allocated pointer (locally)...
fizz[0] = bar;
fizz[1] = bar + 1;
return fizz; // ... and return a COPY of the value of that address!
}
int main()
{
int* out1 = foo(1);
int* out2 = foo(2);
printf("(%d, %d)\n(%d, %d)", out1[0], out1[1], out2[0], out2[1]);
// Don't forget to free the allocated memory...
free(out1);
free(out2);
}
It's not entirely clear whether or not you understand why your first snippet gives the same values for both out1 and out2. So, just in case: the static int fizz[2] line declares a fixed block of memory – though it's only accessible, by name, from within that function. Each call to foo will return a pointer to that (same) memory, and the printf call will display the values assigned to its elements in the most recent (latest) update.
Your first code is also fine, only when to print the result....
int* foo(int bar) {
static int fizz[2]={0,0};
fizz[0] = bar;
fizz[1] = bar + 1;
return fizz;
}
int main() {
int* out1=foo(1);
printf("%d,%d\n", out1[0], out1[1]);
int* out2=foo(2);
printf("%d,%d \n", out2[0], out2[1]);
return 0 ;
}
gives the result :
1,2
2,3

C pass void pointer array to function

I want to pass a void pointer array to a function which fills it with the result it works fine with integer but I have troubles returning char*
int function(void *arr[]);
int main(void) {
void *arr[3];
function(arr);
printf("%d\n", *(int *)&arr[0]);
printf("%d\n", *(int *)&arr[1]);
printf("%s\n", (char *)&arr[2]);
}
int function(void *arr[]){
arr[0] = (void*)(int)4;
arr[1] = (void*)(int)6;
char* test = "abc";
arr[2] = (void*)test;
return 0;
}
for the String I don't get the right value
arr has type void(*)[3].
arr[0] has type void*. The fact that it stores a suitably converted value of 4 is irrelevant.
&arr[0] has type void**.
(int *)&arr[0] has type int*, but it points to an object of type void* instead of pointing to an object of type int. This is not what pointers normally do. You can have such a pointer, but the only thing you can legally do with it is convert it back to the right type, in this case void**. You are not doing that.
*(int *)&arr[0] has type int.
Here you are accessing an object of type void* through an lvalue of type int. This is undefined behaviour. Don't do that.
If you want to convert arr[0] back to int, just do that:
printf("%d\n", (int)arr[0]);
Likewise, if you want to convert arr[2] back to char*, do just that:
printf("%s\n", (char*)arr[2]);
You may pass an array of voids, and assign that array elements to a dynamically allocated memory region that stores the pointed-to value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int function(void *arr[]){
arr[0] = malloc(sizeof(int));
if (arr[0] == NULL) goto ERR_MALLOC_0;
*(int*)arr[0] = 4;
arr[1] = malloc(sizeof(int));
if (arr[1] == NULL) goto ERR_MALLOC_1;
*(int*)arr[1] = 6;
const char *const test = "abc";
arr[2] = malloc(strlen(test));
if (arr[2] == NULL) goto ERR_MALLOC_2;
strcpy(arr[2], test);
return 0;
// remember about error checking
free(arr[2]);
ERR_MALLOC_2:
free(arr[1]);
ERR_MALLOC_1:
free(arr[0]);
ERR_MALLOC_0:
return -1;
}
int main(void) {
void *arr[3];
int err = function(arr);
if (err == -1) abort();
// & is the address of element, not it's element
printf("%d\n", *(int*)arr[0]);
printf("%d\n", *(int*)arr[1]);
printf("%s\n", (char*)arr[2]);
// remember to free memory
for (int i = 0; i < 3; ++i) {
// funny how we do not need to know the effective type
free(arr[i]);
}
}
But such function is just plainly confusing and will result in many, many bugs and problems. Instead just actually use variables of proper type:
#include <stdlib.h>
#include <string.h>
int function(int *val1, int *val2, char **string) {
*val1 = 3;
*val2 = 6;
const char *test = "abc";
*string = malloc(strlen(test));
if (*string == NULL) return -1;
strcpy(*string, test);
return 0;
}
int main(void) {
int val1;
int val2;
char *string;
int err = function(&val1, &val2, &string);
if (err == -1) abort();
printf("%d\n", val1);
printf("%d\n", val2);
printf("%s\n", string);
free(string);
}
If you are really striving for implementing some virtual representation and operations on different data types, using plain "array of void pointers" will get you nowhere, because such array doesn't know what is the underlying type of the value that is being stored - you, as a programmer, have to know what is inside that array (ie. that arr[0] is an int and arr[2] is a char*), so as you know it you might as well just use variables of proper types from the start.
arr[0] = (void*)(int)4;
The above line cast the integer 4 as void pointer (address) and stores it in the array arr as pointer address. I guess that's not what you wanted.
In order to access data using a void pointer the way you want, first make it point to a valid memory address, which will hold the data when the function exits. You have to be careful while assigning memory address to a void pointer inside a function, all variables in that function's stack (local variables) will be popped off the from the stack when the function exits, making that memory addresses invalid. Only use static (or global) or dynamic memory while assigning the memory address to your pointer inside the function, if you want to use it outside the function.

How to fill an array of structs in a function [duplicate]

This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 4 years ago.
I'm trying to create an array of a structure in an external function "add", and print it's fields, but when I get back to the main function "arr" it is still NULL.
I'm confused because I've been creating arrays in external functions many times and it worked.. probably this time the dynamic memory allocation is messing the things up. Can I please get an advice on this matter?
Thanks!
typedef struct {
char* id;
char gender;
char *name;
}Member;
void add(Member arr[], int size);
void print(Member arr[], int *size);
int main()
{
char temp[100];
int size=0;
Member *arr = NULL;
Member *data = (Member*)malloc(sizeof(Member));
//scan fields
gets(temp);
data->id = (char*)malloc((strlen(temp) + 1) * sizeof(char));
strcpy(data->id, temp);
gets(temp);
data->gender = temp;
gets(temp);
data->name = (char*)malloc((strlen(temp) + 1) * sizeof(char));
strcpy(data->name, temp);
add(data, &arr, &size);
print(arr, &size);
return 0;
}
void add(Member *data, Member arr[], int *size)
{
arr = (Member*)realloc(arr, (*size + 1) * sizeof(Member));
arr[*size] = *data;
}
void print(Member arr[], int *size)
{
for (int i = 0;i < *size;i++)
{
puts(arr->id);
puts(arr->gender);
puts(arr->name);
}
}
Imagine code like this:
#include <stdio.h>
void f(int i){
i++;
}
int main(){
int i = 3;
f(3);
printf("%d\n", i);
}
We all know that f() incremented its local copy of i, not the variable that was passed into f() to initially set that value. With that having been said, let's take another look at your add():
void add(Member *data, Member arr[], int *size)
{
arr = (Member*)realloc(arr, (*size + 1) * sizeof(Member));
arr[*size] = *data;
}
When arr is passed into the function, it contains a memory address of the current arr, which starts as NULL. But just like when we change the local value of i in f() above, setting arr to a new value within add() only changes the local value; it does not change main()'s arr.
We also know that if we pass a function an address of data we want it to change, the function can then change the data at that address and the data at that address will reflect the change in the calling function:
#include <stdio.h>
void f(int * i){
*i = *i + 1;
}
int main(){
int i = 3;
f(&i);
printf("%d\n", i);
}
The same logic applies ( though it gets more confusing) when you want to change a pointer's value; send that pointer's address! Let's start with a very simple case:
#include <stdio.h>
#include <stdlib.h>
void f(int** i){
*i = (int*)malloc(sizeof(int));
**i = 99;
}
int main(){
int *i = NULL;
f(&i);
printf("%d\n", *i);
}
Here we create a pointer to an int in main, and initialize it to NULL. Then we send the address of that pointer (that is, the address we stored the NULL) to f(), which (like in your program) allocates some memory and puts the address of the newly allocated pointer _at the address of main's i. Now, the data stored at &i has changed, and dereferencing i from main() will dereference the newly allocated address.
In your code, just as in mine, you'll have to change the way you're passing arr to add() as well as how you interact with it - an exercise you'll get the most out of thinking through yourself. But in short, something like this should get you started:
pass add arr's address, not the address it stores.
Store new address of reallocated memory back to the same address, that is, &arr
make sure to update add() to dereference the pointer to a pointer twice to set the member at the address stored at the address &arr.

Assign the address of local variable to global pointer in C?

I'm newbie in C language. If I assign the address of local variable to global pointer, What happens? Like,
#include <stdio.h>
void func();
int *ptr;
int main()
{
func();
}
void func()
{
int i = 0;
ptr = &i;
}
Is it correct way to assign the address of local variable to global pointer?
It just does what you do, there is nothing wrong about it, except that it probably is not what you want.
So it just assigns the address of i to ptr at the point you assign it. When you leave func this pointer gets invalid.
Note This behaviour is fully defined: The address of i at the place you assign it to the global variable is defined, and so you can assign it. The problem only comes into play later, when you try to dereference the variable after you left the function func. As long as you only use the global variable in func there is no problem in this (except that a global variable is really meaningless).
At this point, this variable doesn't exist anymore. And it is very likely that you either get a segfault or at least you get some strange numbers (because you have overwritten the old stack frame with some other values) in this case.
Just as a side note: What I mean with this stack frame thing. You can try this code on most compilers (without optimizations!)
#include <stdio.h>
int *ptr;
void f1() {
int i = 0;
ptr = &i;
}
void f2() {
int i = 1;
}
int main() {
f1();
printf("%d\n", *ptr);
f2();
printf("%d\n", *ptr);
}
Without optimizations, this will most probably print
0
1
Because the variable i will have the same address when calling f1 and f2 from main().
With optimizations, the call to f2() will be optimized.
Still: This is undefined behavior and must not be done.
Your syntax is correct, but the local variable ceases to exist because it belongs within the scope of the function call's code block. To resolve this, one option is to make the local variable static:
#include <stdio.h>
void func();
int *ptr;
int main()
{
func();
}
void func()
{
static int i = 0;
ptr = &i;
}
Another option would be to allocate new memory within the function call, setting the global pointer to the address of that newly allocated memory:
#include <stdio.h>
void func();
int *ptr = NULL;
int main()
{
func();
}
void func()
{
if(ptr != NULL)
free(ptr);
int *i = (int *)malloc(sizeof(int));
ptr = i;
}
What you've got is syntactically correct, and the code as written is semantically valid (but since ptr is never used, it is a bit pointless).
If you access ptr when it contains a pointer that has gone out of scope, you get undefined behaviour.
However, consider a slightly larger code fragment. Here, the code that sets ptr calls a function that uses ptr, and the variable that ptr points to is still defined, so there is no problem using the pointer.
#include <stdio.h>
void func(void);
void use_pointer(void);
int *ptr;
int main(void)
{
func(); // NB: argument not allowed with prototype!
int i = 20;
printf("%s: A %d\n", __func__, i);
ptr = &i;
use_pointer();
printf("%s: B %d\n", __func__, i);
}
void func(void)
{
int i = 0;
printf("%s: A %d\n", __func__, i);
ptr = &i;
use_pointer();
printf("%s: B %d\n", __func__, i);
}
void use_pointer(void)
{
printf("ptr = %p; *ptr = %d\n", (void *)ptr, *ptr);
*ptr = 42;
}
This is legitimate code — though using global variables is something you should generally avoid and perfectly well could avoid.
Sample output:
func: A 0
ptr = 0x7fff55be74ac; *ptr = 0
func: B 42
main: A 20
ptr = 0x7fff55be74cc; *ptr = 20
main: B 42

Understanding Stack Frames in C

I am trying to understand the stack frame in C, so I wrote a simple C code to analyze the stack frame.
First of all the fun1() returns an address of a local variable which is initialized to 10 to ptr which leads to a warning but that's ok... If I print the value of *ptr now it prints 10, even that's fine...
Next fun2() returns an address of a local variable which is not even initialized and if I try to print the value of *ptr now it prints 10 no matter if i'm returning an address of a or b...
To understand what is actually happening here I made use of gdb.
Using gdb, I started step by step debugging and when I reached the line "return &a" in fun2(), I tried to print address of b, print &b but it printed
Can't take address of "b" which isn't an lvalue.
I don't understand when I try to print the address of a, print &a it prints absolutely fine then why not address of b.
* Why isn't b an lvalue when a is?
# include <stdio.h>
int * fun1() {
int a = 10;
return &a;
}
int * fun2()
{
int a;
int b;
return &a; // return &b;
}
int main ()
{
int *ptr;
ptr = fun1();
ptr = fun2();
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
The compiler is optimizing away some code in fun2.
If you return &a, it is optimizing away int b;. If you return &b, it is optimizing away int a;. If you add some dummy computation, you will see that the addresses of returned values will be different.
int * fun2()
{
int a;
int b;
int* p = &a;
p = &b;
return p;
}
Change main to print the returned values of fun1 and fun2.
int main ()
{
int *ptr;
ptr = fun1();
printf ("ptr = %p, fun1() called...\n", ptr);
ptr = fun2();
printf ("ptr = %p, fun2() called...\n", ptr);
printf ("*ptr = %d, fun2() called...\n", *ptr);
return 0;
}
When I run this code, I get the following sample output:
ptr = 0x7ffff98c70ec, fun1() called...
ptr = 0x7ffff98c70e4, fun2() called...
*ptr = 32749, fun2() called...
It compiles for me just fine when returning the address to b. But you aren't supposed to return the address of a local variable. Check out this link.

Resources