3

I'm a beginner with C and am running into the following problem:

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

void myFunc(char **data);

int main() {
    char **header;
    myFunc(header);
    printf("[In main] %s\n", header[1]); // This gives segmentation fault
    return 0;
}

void myFunc(char **data) {
    data = (char **)malloc(2 * sizeof(char *));
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
}

I can retrieve and print the value of the pointer within the function I allocated the memory for it, but outside of this (in main), it gives segmentation fault.

4
  • to make it compile cleanly change: char **header; to `char **header = NULL; Commented Nov 16, 2015 at 15:56
  • in C, when calling malloc(), 1) do not cast the returned value as it is a void* so can be assigned to any other pointer. Casting just clutter the code and adds headaches to debugging and maintenance of the code. 2) before using the returned value, always check (!=NULL) to assure the operation was successful. Commented Nov 16, 2015 at 15:58
  • this kind of line: data[0] = "test"; needs to be: (*data)[0] = "test"; This line: myFunc(header); passes the contents of header what needs to be passed is the address of header: myFunc( &header ); Commented Nov 16, 2015 at 16:00
  • this line: data = (char **)malloc(2 * sizeof(char *)); is not setting the contents of header to point to the malloc'd area. it should be: *data = malloc(2 * sizeof(char *)); And, of course, check *data for !=NULL before actually using the pointer Commented Nov 16, 2015 at 16:09

2 Answers 2

3

The issue you are having is a little more fundamental to your use of pointers and what happens when you pass a pointer as an argument to a function. When you pass a pointer to a function (just like any variable), the function receives a copy of that pointer (or variable). Meaning that when header is passed to myFunc, myFunc receives a copy of header as data (with its very own, and very different, address):

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

void myFunc(char **data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    myFunc(header);
    printf("[In main] %s\n", header[1]); // This gives segmentation fault
    return 0;
}

void myFunc(char **data) {
    data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", &data);
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
}

Output

$ ./bin/myFunc1

 the address of header in main: 0x7ffd112e27b8

 the address of data in myFunc: 0x7ffd112e2798
[In myFunc] test 2
Segmentation fault

Note: how the address of header in in main is 0x7ffd112e27b8, but when you allocate memory for data in myFunc, you are assigning the starting address for the new block of memory to a pointer at 0x7ffd112e2798. Nothing in main knows anything about memory address 0x7ffd112e2798.

How Do We Fix it?

Just like you do every other time you wish to pass a variable to a function, update that variable, and have the changed value reflected back in the calling function (main here) -- you pass the address of that variable to the function:

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

void myFunc(char ***data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    myFunc(&header);  /* passing address of header to myFunc */
    printf("[In main] %s\n", header[1]);
    return 0;
}

void myFunc(char ***data) {
    *data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", data);
    (*data)[0] = "test";
    (*data)[1] = "test 2";
    printf("[In myFunc] %s\n", (*data)[1]);
}

Now that you have passed the address of header to myFunc as data, when you allocate memory for *data, you are allocating memory and returning the pointer to the same address for header in main. Which allows:

Output

$ ./bin/myFunc2

 the address of header in main: 0x7ffdd72b1968

 the address of data in myFunc: 0x7ffdd72b1968
[In myFunc] test 2
[In main] test 2

Making Use of the Return from myFunc

You can also return the starting address for the new block of memory to main and accomplish the same thing, e.g.:

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

char **myFunc(char **data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    header = myFunc(header);
    printf("[In main] %s\n", header[1]); // This works fine too
    return 0;
}

char **myFunc(char **data) {
    data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", &data);
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
    return data;
}

Output

$ ./bin/myFunc3

 the address of header in main: 0x7ffee22e3298

 the address of data in myFunc: 0x7ffee22e3278
[In myFunc] test 2
[In main] test 2

Now main knows about the address allocated to data in myFunc by virtue of assigning the return to header.

Sign up to request clarification or add additional context in comments.

Comments

1

In principle, you need to allocate the data before calling a function to work on it. You did it the other way around, by allocating data inside the function, it is known inside the function itself but not in main.

In this particular case, you need to:

  • Allocate the memory for data before calling myFunc() (inside that function itself you don't need to allocate the memory for data):

header = (char **)malloc(2 * sizeof(char *));

myFunc(header);

  • Inside myFunc(), there is no need to allocate memory for the two pointers to char as you are using string literals:

data[0] = "test";

However, it is possible to allocate memory for individual char pointer as well:

data[0] = (char *)malloc(15 * sizeof(char));

In that case, you can do strcpy or some other methods to set the content of data[0] and data[1]


Alternatively, all allocation can be done inside myFunc(), but you need to change the prototype to return the proper pointer.

char** myFunc() {
    char **data = (char **)malloc(2 * sizeof(char *));
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]);

    return data;
}

int main() {
    char **header;
    header = myFunc();
    printf("[In main] %s\n", header[1]);
    return 0;
}

6 Comments

Thanks, this fixed it! Just to clarify, once I pass the memory into the function, can I allocate more memory to the elements of array within the function? Like this data[0] = (char *)malloc(15 * sizeof(char));
I think you need two levels of memory allocation; in main allocate the memory for header (which is a pointer to pointer to char). In myFunc you need to allocate for individual char pointer.
There's no reason at all to copy the strings. Using direct assignment is perfectly OK in the above example. The problem with OP's code is a lack of more direct assignments: the actual mistake is in failing to return a value from myFunc such that header is never actually set.
Ok my bad on that particular point of direct assignment - edited that. Apart from that, is there anything wrong about memory allocation in the answer? Can you post a different answer to make your points clear.
Yes. There's no need to allocate memory outside myFunc. You can return allocated memory from functions: OP's mistake is in not returning a value to assign to header. That's all; you're massively overthinking the question.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.