Allocate memory for a pointer to a struct inside a

2019-09-19 05:42发布

问题:

I am trying to write a separate program that calls a function to dynamically allocate memory for a certain number of "student" structs.

My main program was too large to mess with so I created a smaller program to help me more easily figure out what I'm doing:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "memtest.h"

void structMemInit(myName **);

int main(void){

    myName *myNameIs;

    structMemInit(&myNameIs);

    printf("%s\n", myNameIs[1].name);

    return 0;
}

void structMemInit(myName **myNameIs){
    *myNameIs = (myName *) calloc(5, sizeof(myName));
    if(myNameIs == NULL){
        printf("allocating memory didn't work!\n");
        exit(1);
    }
    else if(myNameIs != NULL)
        (*myNameIs)[1].name = "Zach";
}

the memtest.h file is:

typedef struct{
    char *name;
}myName;

All the above program is trying to do is pass a pointer to a struct into the function "structMemInit" and allocate clean space for the struct. Then to see show that it worked, I am setting the variable char to a name. After all this happens, you leave the function and go back to main. Then I print the name in the struct to show it worked.

When run, the program always gives a segfault.

In case you are wondering why I have a separate .h file, my actual program is much larger and has several globally declared structs and I am required by my instructor to keep a separate .h for those structs.

Thanks! Zach

回答1:

If you insist on passing the pointer, it should be by reference, so it's a pointer to a pointer, as the function itslef will modify the address in the pointer.

You're much better off if your function returns a pointer.

//function for allocating the memory
myName *structMemInit(void)
{
    myName *myNameIs = (myName *)calloc(1, sizeof(myName));
    if (myNameIs == NULL) {
        printf("allocating memory didn't work!\n");
        exit(1);
    } else {                     // don't repeat the negation of the condition
        myNameIs->name = "Zach"; // No need for \0, it's automatic
        return myNameIs;
    }
}

//Usage
myName *myNameIs = structMemInit();

BTW it's int main(void) not int main().



回答2:

Before I answer, I should state that I am not too well-versed in C, I am a C++ programmer so there may be a few grammatical errors in what follows. Hopefully though, my point will be made sufficiently for any errors to be of much importance.

The reason you're getting segfault is because of your misunderstanding of what's happening when you pass a pointer as an argument to a function.

Imagine, for instance, your program was the following:

int main(void){
    int i;

    setInteger(i);

    printf("%d\n", i);

    return 0;
}

void setInteger(int n){
    n = 12;
}

In this case, you can clearly see that the output will be undefined because the variable i was not initialised, and was passed by-value to setInteger. Any changes to n are not transferred back to i when the function returns.

If the program were replaced with

int main(void){
    int i;

    setInteger(&i);

    printf("%d\n", i);

    return 0;
}

void setInteger(int *n){
    *n = 12;
}

Then the value output by i will be 12.

The same thing is happening in your program, you're passing your pointer by value.

If you want to pass by reference, you need to do the following:

int main(void){

    myName *myNameIs;

    structMemInit(&myNameIs); // pass the address of your pointer

    printf("%s\n", myNameIs->name);

    return 0;
}

//function for allocating the memory
void structMemInit(myName **myNameIs){ // argument is pointer-to-pointer 
    *myNameIs = (myName *) calloc(1, sizeof(myName)); // dereference pointer to get underlying pointer
    if(*myNameIs == NULL){
        printf("allocating memory didn't work!\n");
        exit(1);
    }
    else{
        *myNameIs->name = "Zach";
    }

}

That's, unfortunately, not the end of your problems. Although you've allocated memory to your myName object, you have not allocated memory to your character array.

To return the string "Zach", you need to do the following:

*myNameIs->name = (char*)malloc(5*sizeof(char)); // need extra char for \0
strcpy(*myNameIs->name, "Zach");


回答3:

Please note that:

typedef struct{
    char name[20];
} myName;

is different from:

typedef struct{
    char *name;
} myName;

In the second form, you are not allocating any space for the string. You are just allocating space for a pointer.

Below is a running version of your program. If you want to use strcpy(p->name, "Zach"); you need to use char name[20]; in your struct.

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

typedef struct{
    // char name[20];
    char *name;
} myName;

myName *structMemInit();

int main(){
    myName *myNameIs;
    myNameIs = structMemInit();
    if (myNameIs)
        printf("%s\n", myNameIs->name);
    return 0;
}

//function for allocating the memory
myName *structMemInit(){
    myName * p = (myName *) malloc(sizeof(myName));
    if (p == NULL){
        fprintf(stderr, "allocating memory didn't work!\n");
    } else {
        fprintf(stderr, "allocating %d memory work!\n", sizeof(myName));
        // strcpy(p->name, "Zach");
        p->name = strdup("Zach");
    }
    return p;
}