Возникают проблемы с назначением указателей на символы в циклах - PullRequest
1 голос
/ 03 февраля 2012

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

struct info {
     char *mystring;
     char *file;
     int line_no;
     struct info *next;
};

Я использую этот цикл для итерации по потоку:

while(1) {      
      char t [KMAX];
      char* file;
      char* line_no;
      char* text;
      if (fgets(t, KMAX, file_pipe) != NULL) {
           file = strtok (t, delimiter);
           line_no = strtok(NULL, delimiter);
           int line = atoi(line_no);
           text = strtok(NULL, delimiter);
           add(&head, text, line, file);
      }

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

Я не уверен, каков правильный метод решения этой проблемы. Должен ли я каким-то образом изменить цикл while и использовать указатели на символы другим способом, или мне следует каким-то образом изменить структуру, чтобы она содержала переменные, вместо того, чтобы просто использовать указатели? Буду признателен за любые отзывы!

РЕДАКТИРОВАТЬ: добавлено больше кода

 void add(struct info **x, char * text, int line_no, char * file) {
 struct info* current = *x;
 struct info* newInfo;


 newInfo = malloc(sizeof(struct info));
 (*newInfo).next = NULL;
 (*newInfo).grepstring = text;
 (*newInfo).line_no = line_no;
 (*newInfo).file = file;

 if (current == NULL) { //indicates the head is null, special case
      *x = newInfo;
 } else {
      //get to the end of the list
      while ((*current).next != NULL) {
           current = (*current).next;
      }
      //apends node to the end of the list
      (*current).next = newInfo;
 }

}

Ответы [ 3 ]

2 голосов
/ 03 февраля 2012

Когда вы говорите char* text, вы выделяете char* в стеке .strtok не указывает на какую-то вновь выделенную память, он указывает на выделенное в стеке пространство t.

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

Вам необходимо содержимое каждого struct info, чтобы пережить цикл(и, по-видимому, продолжать выживать в обозримом будущем).Для этого вы должны сделать выделение кучи .В C это делается с помощью функции malloc.

В вашем методе add произнесите:

char* text_copy = malloc(strlen(text)+1); // +1 for trailing NUL character
strcpy(text_copy, text);

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

Вы должны сделать это для всего содержимого struct info, поскольку в данный момент они все указатели в выделенный стеком t буфер.

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

1 голос
/ 03 февраля 2012

Единственный буфер, который вы когда-либо создавали для хранения строк, был t, который вы создали в верхней части цикла while:

char t [KMAX];

Так что все ваши char * указатели будут указывать куда-то вэтот буфер, но это проблема, потому что вы меняете содержимое буфера каждый раз, когда вы вызываете fgets.После того как вы закончили чтение ввода, единственным текстом, который вы фактически сохранили в ОЗУ, будут данные последнего вызова fgets.

. Вы можете изменить функцию add, чтобы она распределяла новые буферы икопирует строки для них.Уже есть функция, которая делает это для вас, и она называется strdup .Примерно так будет работать (хотя я не проверял):

void add(struct info **x, char * text, int line_no, char * file) {
 ...
 newInfo = malloc(sizeof(struct info));
 newInfo->next = NULL;
 newInfo->grepstring = strdup(text);
 newInfo->line_no = line_no;
 newInfo->file = strdup(file);
 ...
}
1 голос
/ 03 февраля 2012

Вы не показываете нам, что делает add(), но, очевидно, он просто присваивает результаты вызова strtok() непосредственно членам структуры. Вы не можете этого сделать - используйте strdup() (или malloc() и strcpy()), чтобы сделать копию каждого char * перед назначением их члену структуры. Указатели strtok() возвращают точку в этот буфер char, и они становятся недействительными с каждой новой итерацией цикла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...