【问题标题】:Pointer problem in C for char*C 中用于 char* 的指针问题
【发布时间】:2010-03-17 20:16:20
【问题描述】:

我使用指针来保存名称和研究实验室属性。但是当我打印现有的顶点时,当我打印顶点时,我无法正确看到所谓的属性。 例如,虽然 name 的实际值是 "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");
    }

【问题讨论】:

    标签: c char printing


    【解决方案1】:

    当你这样做时:

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

    您正在将 指针 复制到字符串 nameresearchLab。您不是在复制 strings 本身。换句话说,在这之后,newV->namename 指向内存中存储名称的完全相同的位置;您尚未创建数据的副本。

    由于您随后继续覆盖createNewPerson 函数中的name 数组,因此在此函数结束时,您的所有vertex 结构将具有它们的name 属性指向相同的内存位置,这仅存储输入的姓氏。

    更糟糕的是,当createNewPerson 返回时,它的本地name 数组超出范围,并被重新用于其他事情。由于您的顶点结构仍然指向此处以获取其name 属性,这就是您获得垃圾的方式。

    您需要复制字符串。一个简单的方法是:

    newV->name = strdup(name);
    

    您需要#include <string.h> 才能获得strdup 库函数。

    然后,您还需要确保在处理vertex 结构时调用name 属性上的free

    【讨论】:

      【解决方案2】:

      GRAPHinsertVnameresearchLab 字符串的指针 复制到向量结构中。

      createNewPersonnameresearchLab 字符串创建一个临时

      这里的问题是,当您在createNewPerson 返回后访问它时,您指向的临时 字符串会导致未定义的行为

      要解决这个问题,您可以使用malloc+strcpy 或使用非标准的strdup 复制GRAPHinsertV 中的字符串。

      【讨论】:

      • strdup 可能不是 ISO C,但它是 POSIX,所以它只是select 等意义上的“非标准”。人。是“非标准的”。
      • @Tyler,是的,我在strdup 上做作业,并意识到它不是我想象的 GNU 扩展,而是 POSIX 标准的一部分。不过,我认为最好将这张纸条留在 cmets 中。
      【解决方案3】:

      您传递给 GRAPHinsertV() 的名称变量是在堆栈上为 createNewPerson() 分配的,因此指针指向一个局部变量。一旦激活记录被弹出,该值可以(并且将)被后续代码覆盖。

      如果您只想在结构中保留一个 char *,则需要在堆上分配内存。

      例如。而不是

      char name[30];
      

      你可以使用

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

      但请记住,如果您手动分配它,您也必须注意释放它,否则会出现内存泄漏。

      【讨论】:

        【解决方案4】:

        当你分配 char *name 指针时,比如

        newV->name=name;
        

        您不是在创建一个新字符串,而是让 newV.name 成员指向与传入的 char[] 数组相同的内存。您需要 malloc() 或以其他方式分配一个新的 char[ ] 数组,以便为​​每个结构获得单独的存储。

        【讨论】:

          【解决方案5】:

          这里有问题:

          Vertex newV = malloc(sizeof newV);
          

          应该是

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

          【讨论】:

          • 我猜Vertexvertex* 的typedef,因为大小写不同。
          【解决方案6】:

          您正在函数createNewPerson() 中分配内存,该内存与createNewPerson() 执行的时间完全相同,并且可以在它返回后立即覆盖。您需要使用strdup(newV->name, name) 之类的内容复制文本字段,而不是指向createNewPerson() 中的局部变量。 (如果您的实现没有strdup(),您可以轻松地将其定义为:

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

          此外,您的 I/O 存在潜在问题。如果您输入我的名字“David Thornley”作为名称,它将以“David”作为名称,“Thornley”作为实验室,因为“%s”搜索以空格分隔的字符串。如果我输入“四十二”作为ID,则id 将不输入任何内容,而名称将使用“四十二”。如果我输入超过 29 个字符的名称或实验室名称,它将覆盖其他内存。

          我建议使用fgets() 为每个答案获取一行输入,然后使用sscanf() 对其进行解析。

          【讨论】:

            【解决方案7】:

            在传递和分配字符串时,请始终复制它们。不能保证您收到的字符串之后仍然在内存中,因为指针可能已被释放。

            当然,如果你只打算在函数内部使用name(也就是说,你不会将它分配给函数范围之外的变量),你不需要'不必复制。

            为了做到这一点,在GRAPHinsertV 中,而不是

            newV->name=name;
            

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-07-09
              • 2014-05-13
              • 2021-02-28
              • 2021-11-26
              相关资源
              最近更新 更多