Объявление неожиданного поведения - PullRequest
0 голосов
/ 25 января 2019

Итак, у меня есть две простые программы.Они очень похожи, но один код работает просто отлично, а другой вообще не работает.Кто-нибудь здесь представляет, почему?

Этот код работает без проблем, несмотря на то, что имя char * не инициализируется.

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

int main(int argc, char* argv[]){

   DIR* d;
   struct dirent* dir;
   char* name;
   d=opendir(".");
   if(d){
        while((dir=readdir(d))!=NULL){
             strcpy(name,dir->d_name);
             printf("%s\n",name);
        }
        clode(dir);
   }
  return 0;
}

Второй код имеет незначительное отличие в разделе объявлений, и это приводит к недоступности переменной name..

int main(int argc, char* argv[]){

   DIR* d;
   struct dirent* dir;
   char* surname = "Surname";
   char* name;
   d=opendir(".");
   if(d){
        while((dir=readdir(d))!=NULL){
             strcpy(name,dir->d_name);
             printf("%s\n",name);
        }
        clode(dir);
   }
  return 0;
}

При выполнении второго кода я получаю «Ошибка сегментации» сразу после strcpy(name,dir->d_name), и когда я пытаюсь напечатать переменную «name» в отладчике GDB, я получаю сообщение $1 = 0x1 <error: Cannot access memory under address 0x1>.Почему это сообщение об ошибке не появилось в первой программе?И что за проблема с объявлением char* surname = "Surname";, приводящим к такого рода ошибкам во время выполнения?

PS Я знаю, что в этом примере я никогда не использую переменную 'фамилия', и я знаю, что strcpy(name,dir->d_name) не требуетсяв этом коде.Этот код является частью гораздо большего кода, и это является результатом извлечения важных частей, которые вызывают ошибку (в попытке создать более минимальный набор кода).

Спасибо.Привет

Ответы [ 2 ]

0 голосов
/ 25 января 2019

char* name; неинициализирован ... там, где он указывает, не определено. Это может сработать. В мае нет.

Добавление char* surname = "Surname" немного меняет ваши переменные, позволяя name указать куда-то еще.

Что вам действительно нужно, так это char name[NAME_MAX] для выделения предсказуемого хранилища.

0 голосов
/ 25 января 2019

Поскольку имя не инициализировано, попытка использовать strcopy с ним - неопределенное поведение. Это означает, что все, что происходит, является непредсказуемым и плохим кодом (этот не означает, что будет терпеть неудачу, просто могут случиться плохие вещи, и должен потерпеть неудачу. В целом , UB может все равно закончить, что может случиться.)

Один из способов исправить эту ошибку - что-то вроде:

int main(int argc, char* argv[]){

   DIR* d;
   struct dirent* dir;
   char* surname = "Surname";
   char* name = NULL;

   d=opendir(".");
   if(d){
        while((dir=readdir(d))!=NULL){
             name = realloc(name, strlen(d->name)+1); // Needs to be one char longer 
                                                      // to account for the null terminator.
             strcpy(name,dir->d_name);
             printf("%s\n",name);
        }
        free(name);
        clode(dir);
   }
  return 0;
}
...