简体   繁体   English

C中的char指针问题*

[英]Pointer problem in C for char*

i use pointer for holding name and research lab property. 我使用指针来持有名称和研究实验室的财产。 But when i print the existing Vertex ,when i print the vertex, i cant see so -called attributes properly. 但是当我打印现有的顶点时,当我打印顶点时,我看不到所谓的属性。 For example though real value of name is "lancelot" , i see it as wrong such as "asdasdasdasd" 例如,尽管名称的实际值是“ lancelot” ,但我认为它是错误的,例如“ asdasdasdasd”

struct vertex {
                int value;
                char*name;
                char* researchLab;
                struct vertex *next;
                struct edge *list;
};
    void GRAPHinsertV(Graph G, int value,char*name,char*researchLab) {
    //create new  Vertex.
        Vertex newV = malloc(sizeof newV);
        // set  value of new variable  to which belongs the person.
        newV->value = value;
        newV->name=name;
        newV->researchLab=researchLab;
        newV->next = G->head;
        newV->list = NULL;
        G->head = newV;
        G->V++;
    }

    /***
    The method   creates new person.
    **/
    void createNewPerson(Graph G) {
        int id;
        char name[30];
        char researchLab[30];
        // get requeired variables.
        printf("Enter id of the person to be added.\n");
        scanf("%d",&id);
        printf("Enter name of the person to be added.\n");
        scanf("%s",name);
        printf("Enter researc lab of the person to  be added\n");
        scanf("%s",researchLab);
        // insert the people to the social network.
        GRAPHinsertV(G,id,name,researchLab);
    }
    void ListAllPeople(Graph G)
    {
        Vertex tmp;
        Edge list;
        for(tmp = G->head;tmp!=NULL;tmp=tmp->next)
        {
            fprintf(stdout,"V:%d\t%s\t%s\n",tmp->value,tmp->name,tmp->researchLab);

        }
        system("pause");
    }

When you do this: 执行此操作时:

   newV->name=name;
   newV->researchLab=researchLab;

You are copying the pointer to the strings name and researchLab . 您正在将指针复制到字符串nameresearchLab You are not copying the strings themselves. 您不是在复制字符串本身。 In other words, after this, newV->name and name point to exactly the same location in memory where the name is stored; 换句话说,此后, newV->namename指向name在内存中存储的位置完全相同; you have not created a duplicate copy of the data. 您尚未创建数据的重复副本。

Since you then proceed to overwrite the name array in the createNewPerson function, at the end of this function, all of your vertex structs will have their name attribute pointing to the same memory location, which is only storing the last name entered. 由于您随后将继续覆盖createNewPerson函数中的name数组,因此在该函数结束时,所有vertex结构的name属性都指向相同的内存位置,该内存位置仅存储输入的姓氏。

Worse, when createNewPerson returns, its local name array goes out of scope, and is re-used for other things. 更糟糕的是,当createNewPerson返回时,其本地name数组超出范围,并被重新用于其他用途。 Since your vertex structs are still pointing here for their name attributes, this is how you get garbage. 由于您的顶点结构仍指向其name属性,因此这就是获取垃圾的方法。

You need to duplicate the string. 您需要复制字符串。 A simple way to do it is: 一种简单的方法是:

newV->name = strdup(name);

You will need to #include <string.h> to get the strdup library function. 您将需要#include <string.h>来获取strdup库函数。

And then you also need to make sure that you call free on the name attribute whenever you are disposing of a vertex structure. 然后,还需要确保在处置vertex结构时,对name属性进行free调用。

GRAPHinsertV copies the pointer of the name and researchLab strings to the vector structure. GRAPHinsertVname指针researchLab字符串复制到向量结构。

createNewPerson creates a temporary for the name and researchLab strings. createNewPersonnameresearchLab字符串创建一个临时目录

The problem here is, you're pointing to a temporary string which causes undefined behaviour when you access it after createNewPerson returns. 这里的问题是,您指向一个临时字符串,该字符串在createNewPerson返回后访问它时会导致未定义的行为

To solve this problem, you can duplicate the strings in GRAPHinsertV using malloc + strcpy , or by using the non-standard strdup . 要解决此问题,可以使用malloc + strcpy或使用非标准的strdupGRAPHinsertV复制字符串。

The name variable you pass to GRAPHinsertV() is allocated on the stack for createNewPerson(), so the pointer points to a local variable. 传递给GRAPHinsertV()的名称变量在堆栈上分配给createNewPerson(),因此指针指向局部变量。 Once the activations records are popped off that value can (and will) be overwritten by subsequent code. 一旦激活记录弹出,该值就可以(并且将被)后续代码覆盖。

You need to allocate memory on the heap if you are only going to keep a char * in the struct. 如果仅要将char *保留在结构中,则需要在堆上分配内存。

Ex. 例如 Instead of 代替

char name[30];

you could use 你可以用

char *name = (char *)malloc(30*sizeof(char));

but keep in mind if you manually allocate it you have to take care of freeing it as well, otherwise it will have a memory leak. 但请记住,如果您手动分配它,则还必须注意释放它,否则它将发生内存泄漏。

When you assign the char *name pointer, like 当您分配char * name指针时,例如

newV->name=name;

You're not creating a new string, but making the newV.name member point to the same memory as the char[] array that was passed in. You'll need to malloc() or otherwise allocate a new char[] array in order to obtain separate storage for each structure. 您不是在创建新字符串,而是使newV.name成员指向与传入的char []数组相同的内存。您将需要malloc()或在其中分配一个新的char []数组。为了获得每个结构的单独存储。

There's a problem here: 这里有个问题:

Vertex newV = malloc(sizeof newV);

It should be 它应该是

Vertex *newV = malloc(sizeof(Vertex));

You are allocating memory in the function createNewPerson() that lasts exactly as long as createNewPerson() is executing, and is available for overwriting immediately after it returns. 您正在函数createNewPerson()中分配内存,该内存的持续时间与createNewPerson()正在执行的时间完全一样,并且可以在返回后立即覆盖。 You need to copy the text fields in with something like strdup(newV->name, name) , rather than point to the local variables in createNewPerson() . 您需要使用诸如strdup(newV->name, name)类的东西来复制文本字段,而不是指向createNewPerson()的局部变量。 (If your implementation doesn't have strdup() , you can easily define it as: (如果您的实现没有strdup() ,则可以轻松地将其定义为:

char * strdup(const char *inp)
{
    char * s = malloc(strlen(inp) + 1);
    strcpy(s, inp);
    return s;
}

In addition, your I/O has potential problems. 另外,您的I / O可能存在问题。 If you enter my name, "David Thornley", for the name, it'll take "David" as the name and "Thornley" as the lab, since "%s" searches for a whitespace-delimited string. 如果输入我的名字“ David Thornley”作为名称,则将以“ David”作为名称,以“ Thornley”作为实验室,因为“%s”搜索以空格分隔的字符串。 If I enter "Forty-two" for the ID, nothing will be put in id , and "Forty-two" will be used for the name. 如果我输入“ 42”作为ID,则不会在id放置任何内容,而“ 42”将用作名称。 If I enter a name or lab name over 29 characters, it will overwrite other memory. 如果我输入的名称或实验室名称超过29个字符,它将覆盖其他内存。

I'd suggest using fgets() to get one line of input per answer, then use sscanf() to parse it. 我建议使用fgets()获得每个答案的一行输入,然后使用sscanf()进行解析。

When passing and assigning strings, always make a copy of them. 传递和分配字符串时,请始终复制它们。 There're no guarantees that the string you received is still in the memory afterwards, since the pointer could have been freed. 由于指针可能已经释放,因此不能保证以后收到的字符串仍在内存中。

Of course, if you are only going to use name inside the function (that's, you're not going to assign it to a variable outside the scope of the function), you don't have to do the copy. 当然,如果仅在函数内部使用name (也就是说,您不会将其分配给函数范围以外的变量),则不必执行复制操作。

In order to do that, inside GRAPHinsertV , instead of 为此,请在GRAPHinsertV ,而不是

newV->name=name;

do

if (name != NULL)     // Preventing using null pointer
{
    newV->name = malloc(strlen(name)+1);
    strcpy(newV->name, name);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM