Проблема указателя в C для символа * - PullRequest
0 голосов
/ 17 марта 2010

Я использую указатель для хранения имени и свойства исследовательской лаборатории. Но когда я печатаю существующую вершину, когда я печатаю вершину, я не вижу должным образом так называемые атрибуты. Например, хотя реальное значение имени "ланселот" , я считаю его неправильным, например "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");
    }

Ответы [ 7 ]

5 голосов
/ 17 марта 2010

Когда вы делаете это:

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

Вы копируете указатель в строки name и researchLab. Вы не копируете сами строки . Другими словами, после этого newV->name и name указывают на одно и то же место в памяти, где хранится имя; Вы не создали дубликат копии данных.

Поскольку затем вы перезаписываете массив name в функции createNewPerson, в конце этой функции все ваши структуры vertex будут иметь свой атрибут name, указывающий на ту же область памяти, которая хранит только введенную фамилию.

Хуже того, когда возвращается createNewPerson, его локальный массив name выходит из области видимости и повторно используется для других целей. Поскольку ваши вершинные структуры все еще указывают здесь на свои атрибуты name, именно так вы и получаете мусор.

Вам нужно продублировать строку. Простой способ сделать это:

newV->name = strdup(name);

Вам потребуется #include <string.h>, чтобы получить библиотечную функцию strdup.

И затем вам также нужно убедиться, что вы вызываете free для атрибута name всякий раз, когда вы используете структуру vertex.

4 голосов
/ 17 марта 2010

GRAPHinsertV копирует указатель строк name и researchLab в векторную структуру.

createNewPerson создает временную для строк name и researchLab.

Проблема здесь в том, что вы указываете на временную строку, которая вызывает неопределенное поведение при доступе к ней после возврата createNewPerson.

Чтобы решить эту проблему, вы можете продублировать строки в GRAPHinsertV с помощью malloc + strcpy или с использованием нестандартного strdup.

0 голосов
/ 17 марта 2010

При передаче и назначении строк всегда делайте их копию. Нет никаких гарантий, что полученная вами строка все еще будет в памяти, поскольку указатель мог быть освобожден.

Конечно, если вы собираетесь использовать name только внутри функции (то есть вы не собираетесь назначать ее переменной вне области действия функции), вы нужно сделать копию.

Для этого внутри GRAPHinsertV вместо

newV->name=name;

до

if (name != NULL)     // Preventing using null pointer
{
    newV->name = malloc(strlen(name)+1);
    strcpy(newV->name, name);
}
0 голосов
/ 17 марта 2010

Вы выделяете память в функции createNewPerson(), которая длится ровно столько, сколько выполняется createNewPerson(), и доступна для перезаписи сразу после ее возврата. Вам нужно скопировать текстовые поля с чем-то вроде strdup(newV->name, name), а не указывать на локальные переменные в createNewPerson(). (Если ваша реализация не имеет strdup(), вы можете легко определить ее как:

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

Кроме того, ваш ввод / вывод имеет потенциальные проблемы. Если вы введете мое имя «Дэвид Торнли» в качестве имени, в качестве имени будет выбран «Дэвид», а в качестве лаборатории - «Торнли», так как «% s» ищет строку с пробелами. Если я введу «Сорок два» для идентификатора, ничего не будет введено в id, а «Сорок два» будет использовано для имени. Если я введу имя или название лаборатории более 29 символов, оно перезапишет другую память.

Я бы предложил использовать fgets() для получения одной строки ввода для ответа, а затем использовать sscanf() для его анализа.

0 голосов
/ 17 марта 2010

Здесь проблема:

Vertex newV = malloc(sizeof newV);

должно быть

Vertex *newV = malloc(sizeof(Vertex));
0 голосов
/ 17 марта 2010

Когда вы назначаете указатель на имя char *, например

newV->name=name;

Вы не создаете новую строку, но заставляете член newV.name указывать на ту же память, что и переданный массив char []. Вам потребуется malloc () или иным образом выделить новый char [ ] массив для получения отдельного хранилища для каждой структуры.

0 голосов
/ 17 марта 2010

Переменная имени, которую вы передаете GRAPHinsertV (), выделяется в стеке для createNewPerson (), поэтому указатель указывает на локальную переменную. После того, как записи активации активированы, это значение может (и будет) перезаписано последующим кодом.

Вам нужно выделить память в куче, если вы собираетесь хранить только символ * в структуре.

Ex. Вместо

char name[30];

вы можете использовать

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

но имейте в виду, что если вы выделите его вручную, вы также должны позаботиться о его освобождении, иначе это приведет к утечке памяти.

...