Gomu
Gomu

Reputation: 1064

C - Returning array as function argument

I was trying to pass a character array 'p' to a function 'func' and getting it copied to another argument 'arg' inside the function. But, the array is not getting copied, though I'm able to modify the content of 'p' in the 'func' and able to verify the changes in the main function, the 'res' doesn't get copied with the values from 'p'. It prints blank. I'm not sure what mistake I'm making.

#include <stdio.h>
#include <stdlib.h>

void func(char *c, int size, char *res)
{
        int i;
        printf("Printing c in func...\n");
        for(i=0;i<size;i++) {
                printf("%c",c[i]);
        }
        printf("\n");
        c[2] = 'j';
        res = c;
}

int main(void)
{
        char c[5]={'h','e','l','l','o'};
        char *p,*arg;
        int i, size = 5;
        p=c;
        arg = (char*)malloc(size);
        func(p,size,arg);
        printf("Printing p in main...\n");
        for(i=0;i<size;i++) {
                printf("%c",p[i]);
        }
        printf("\n");
        printf("Printing arg in main...\n");
        for(i=0;i<size;i++) {
                printf("%c",arg[i]);
        }
        printf("\n");

        return 0;
}

Output:

Printing c in func...
hello
Printing p in main...
hejlo
Printing arg in main...

Upvotes: 1

Views: 55

Answers (2)

haccks
haccks

Reputation: 106102

In C, arguments to a function are passed by value. The location res and c does not exists after function execution reaches its end. Note that the changes you are doing is with the pointers itself and not the location pointer points to. So any changes to res will not be visible to main.

To make the changes visible to main you need to pass address of arg to function func.

func signature should be

void func(char *c, int size, char **res) ;  

and its call from main should be

func(p, size, &arg);  

Also change the assignment res = c; to *res = c; in function func.

In this case you are passing the address of pointer arg and changes are done to the location res is pointing to. res is pointing to the address of reg so any changes to the address pointed by res will be persist and visible to main.

Now see how it works. Initially when you call your function func after the suggested changes:

      +-----------+                (0x300 is a random memory location)
      |           |
arg   |   0x300   | <---------+
      |           |           |
      +-----------+           |
        0x100                 |
                              |
                              |
      +-----------+           |
      |           |           |
res   |   0x100   +-----------+
      |           |
      +-----------+
         0x200

When you assign c to *res (an alias of reg), *res will make reg to point to where c points to. Assuming string hello is stored at 0x500 then *res = c will make reg to point to 0x500:

                                                            Array c (in main)
      +-----------+                                  +-----+-----+-----+-----+-----+------+
      |           +--------------------------------->+ 'h' | 'e' | 'j' | 'l' | 'o' | '\0' |
arg   |   0x500   | <---------+                      +-----+-----+-----+-----+-----+-------                                      
      |           |           |                       0x500  .... 
      +-----------+           |
        0x100                 |
                              | *res = c
                              |
      +-----------+           |
      |           |           |
res   |   0x100   +-----------+
      |           |
      +-----------+
         0x200

Upvotes: 2

4pie0
4pie0

Reputation: 29744

In C pointers ar epassed by value to functions, so in your function:

void func(char *c, int size, char *res)

res is a totally different object than pointer passed to it

func(p, size, arg);

that is it is different than arg, but it points (only points) to the same location as arg pointed at the time it was passed to this function.

Therefore assignment

res = c;

mad inside that function changes only local pointer (the one inside the function). If you instead did

*res = *c;

then the memory pointed to would be changed and that would be visible from the outside of the function as the memory pointed to by original pointer is same as the one pointed by res. This is also why writing 'j' to c[2] changes original array:

c[2] = 'j'; /* note: this is same as *(c + 2) = 'j'; and this is why it works - you
               are using memory pointed to by pointer */

If you need to change the pointer itself you need to pass address to that pointer instead:

void func(char *c, int size, char **res)

Upvotes: 1

Related Questions