2015-04-08 3 views
1

Я начинаю программировать на C, и я написал код спецификации спецификации, но я постоянно получаю ошибку сегментации и не могу продолжать движение вперед. Если имя файла является «code.c», и оно выполняется с ошибкой, не передающей аргумент (имя файла). Но если имя файла передано, мы приземляемся в Segmentation Fault. Любая помощь/предложения будут оценены.C Сегментация программ Неисправность main()

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



struct _data 
{    
    char *firstName; 
    char *lastName; 
    long number; 
}; 

// SCAN FILE 
int SCAN(FILE *(*stream)) 
{ 
    *stream = fopen("inputFile.data", "r"); 

    int ch = 0, lines = 0; 

    while (!feof(*stream)) 
    { 
     ch = fgetc(*stream); 
     if (ch == '\n') 
     { 
      lines++; 
     } 
    } 
    return lines; 
} 

// LOAD FILE 
struct _data *LOAD(FILE *stream, int size) 
{ 
    int i; 
    size_t chrCount; 
    char *text, *number, *firstName, *lastName; 
    struct _data *BlackBox; 

    if ((BlackBox = (struct _data*)calloc(size, sizeof(struct _data))) == NULL) 
    { 
      printf("ERROR - Could not allocate memory.\n"); 
      exit(0); 
    } 

    rewind(stream); 


    for (i = 0; i < size; i++) 
    { 
     getline(&text, &chrCount, stream); 
     firstName = strtok(text, " "); 
     lastName = strtok(text, " "); 
     number  = strtok(NULL, "\n"); 

     // Allocate memory for name part of struct. 
     if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName), sizeof(char))) == NULL) 
     { 
      printf("ERROR - Could not allocate memory.\n"); 
      exit(0); 
     } 
     if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName), sizeof(char))) == NULL) 
     { 
      printf("ERROR - Could not allocate memory.\n"); 
      exit(0); 
     } 

     strcpy(BlackBox[i].firstName, firstName); 
     strcpy(BlackBox[i].lastName, lastName); 
     BlackBox[i].number = atol(number); 
    } 
    fclose(stream); 
    return BlackBox; 
} 


void SEARCH(struct _data *BlackBox, char *name, int size, int inputs) 
{ 
    int i; 
    int found = 0; 
    char *search = " "; 
    char *firstName; 
    char *lastName; 

    if (inputs == 2) 
    { 
     firstName = strtok(name, search); 
     lastName = strtok(NULL, search); 
    } 


    printf("*******************************************\n"); 
    if (inputs == 2) 
    { 
     for (i = 0; i < size; i++) 
     {   
      if (!strcasecmp(firstName, BlackBox[i].firstName) && !strcasecmp(firstName, BlackBox[i].firstName)) 
      { 
       printf("The name was found at the %d entry.\n", i); 
       found = 1; 
       break; 
      } 
     } 
    } 
    else 
    { 
     for (i = 0; i < size; i++) 
     {   
      if (!strcasecmp(firstName, BlackBox[i].firstName) || !strcasecmp(firstName, BlackBox[i].firstName)) 
      { 
       printf("The name was found at the %d entry.\n", i); 
       found = 1; 
       break; 
      } 
     } 
    } 

    if (found == 0) 
    { 
      printf("The name was NOT found.\n"); 
    } 
    printf("*******************************************\n"); 
} 

// FREE MEMORY 
void FREE(struct _data *BlackBox, int size) 
{ 
    int i; 
    for (i = 0; i < size; i++) 
    { 
     free(BlackBox[i].firstName); 
     free(BlackBox[i].lastName); 
    } 
    free(BlackBox); 
    BlackBox = NULL; 
} 


// MAIN 
int main(int argv, char **argc) 
{ 
    int size; 
    FILE *stream; 
    struct _data *BlackBox; 

    // argv == 1 WORKS, Below message is printed. 
    if (argv == 1) 
    {   
     printf("*******************************************\n"); 
     printf("* You must include a name to search for. *\n"); 
     printf("*******************************************\n"); 
    } 
    // argv == 2 DOES NOT WORK, Segmentation Fault.  
    if (argv == 2) 
    { 
     size = SCAN (&stream); 
     BlackBox = LOAD(stream, size); 
     SEARCH(BlackBox, argc[1], size, 1); 
    } 
    if (argv == 3) 
    { 
     size = SCAN(&stream); 
     BlackBox = LOAD(stream, size); 
     SEARCH(BlackBox, argc[2], size, 2); 
    } 
    return 0; 
} 
+3

Вы никогда не проверяете, выполнено ли 'fopen()'! И ['while (! Feof (file))] (http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong) всегда ошибочно. –

+0

Вы пытались запустить 'pstack' в файле ядра, оставленном после сбоя (при условии, что вы правильно настроили свои параметры дампа в своей системе) или запустите его в отладчике, таком как gdb, поэтому, когда он сбой, вы можете узнать строку #? Когда программа segv в первую очередь вам нужно сделать, это выяснить, в какой строке она происходит. – clearlight

+0

На самом деле '' pstack работает на Solaris, но, возможно, не на Linux, но это необходимо: 'GDB путь/к/Основной файл/' ' (GDB) where' ' (GDB) нить применить все bt' – clearlight

ответ

0

У вас есть проблема в этом коде:

firstName = strtok(text, " "); 
    lastName = strtok(text, " "); 
    number  = strtok(NULL, "\n"); 

...

BlackBox[i].number = atol(number); 

Второй strtok() вызов должен пройти NULL в качестве первого аргумента. Как бы то ни было, третий вызов strtok()определен, чтобы вернуть NULL, потому что первый вызов изменяет text таким образом, что второй потребляет все это (при повторном значении с самого начала, как это ошибочно делает). Однако вы не проверяете это, и в результате atol() пытается разыменовать нулевой указатель.

Update:

Кроме того, как заметил @chqrlie и позже @JamesWilkins, не выделяют достаточно места для BlackBox[i].firstName и BlackBox[i].lastName, как вам нужно место для струнных терминаторов, а также. Это совершенно отдельная проблема, которая могла бы также произвести segfault. Мне нравится предложение @ chqrlie переключиться на strdup(), но этого было бы достаточно, чтобы просто увеличить каждое выделение на единицу.

Update 2:

Кроме того, у вас есть проблема с этой линией:

getline(&text, &chrCount, stream); 

Вы не инициализируете переменную text перед первым вызовом, поэтому он содержит значение нежелательного. Функция выделяет буфер только тогда, когда его первый аргумент указывает на указатель NULL; иначе он записывает строку в буфер, на который указывает указатель, полученный путем разыменования первого аргумента. Запись в случайное место в памяти, безусловно, приводит к неопределенному поведению, которое на практике часто проявляется как segfault.

Кроме того, если вы не можете полагаться на нет строки файла, который длиннее, чем первый, также необходимо освободить text указатель в конце каждой итерации цикла и сбросить его значение NULL, так что getline() выделяет свежий буфер на следующей итерации. Если вы не освобождаете его на каждой итерации, тогда вам нужно освободить его после окончания цикла; иначе вы будете утечка памяти.

+0

Я пытаюсь прочитать файл, содержащий строку в этом формате «John Doe 777777», и я пытаюсь разбить их в форме «firstName, lastName, number». – user3337714

+0

Я сказал вам, что второй вызов 'strtok()' должен передать 'NULL' в качестве первого аргумента. Так вы инструктируете его возвращать токен * next * вместо повторного токенирования с самого начала. В качестве вторичного - но тем не менее важного - вы всегда должны проверять возвращаемое значение 'strtok()', чтобы обработать ошибки во входных данных более изящно, чем сбой. –

+0

Я внесла изменения . 'lastName = strtok (NULL, ""); "и я все равно получаю ту же ошибку. – user3337714

0

Попробуйте это (хотя я использую Visual Studio для Windows). Я добавил код, чтобы проверить отсутствие «\ n» в последней строке, а также разрешено переменное количество поисковых запросов. Я также увеличил выделение памяти для строк на 1, чтобы учесть нулевой завершающий символ. Я заметил, что вы используете getline(const char*..., и я думаю, что это GNU (Linux?), Поэтому я меняю это на fgets(), чтобы я мог скомпилировать и протестировать его в VS (чтобы вы могли изменить его, если хотите). Я также поставил различные нулевые проверки, чтобы быть более безопасным.

#include <iostream> 

using namespace std; 

struct _data 
{ 
    char *firstName; 
    char *lastName; 
    long number; 
}; 

// SCAN FILE 
int SCAN(FILE *(*stream)) 
{ 
    *stream = fopen("inputFile.data", "r"); 
    if (*stream == NULL) 
    { 
     perror("Error opening file"); 
     return 0; 
    } 

    char ch = 0, lines = 0, linesize = 0; 

    while ((ch = fgetc(*stream)) != EOF) 
    { 
     if (ch == '\n') 
     { 
      lines++; 
      linesize = 0; 
     } 
     else linesize++; 
    } 

    if (linesize > 0) 
     lines++; // (last line doesn't have '\n') 

    return lines; 
} 

// LOAD FILE 
struct _data *LOAD(FILE *stream, int lineCount) 
{ 
    int i; 
    size_t chrCount = 256; 
    char text[256], *result, *number, *firstName, *lastName; 
    struct _data *BlackBox; 

    if ((BlackBox = (struct _data*)calloc(lineCount, sizeof(struct _data))) == NULL) 
    { 
     printf("ERROR - Could not allocate memory.\n"); 
     exit(0); 
    } 
    else memset(BlackBox, 0, sizeof(struct _data) * lineCount); // (make sure all data members are null to begin) 

    rewind(stream); 


    for (i = 0; i < lineCount; i++) 
    { 
     result = fgets(text, chrCount, stream); 
     if (result == NULL) 
      break; // (EOF) 

     firstName = strtok(text, " "); 
     lastName = strtok(NULL, " "); 
     number = strtok(NULL, "\n"); 

     // Allocate memory for name part of struct. 
     if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName) + 1, sizeof(char))) == NULL) 
     { 
      printf("ERROR - Could not allocate memory.\n"); 
      exit(0); 
     } 
     if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName) + 1, sizeof(char))) == NULL) 
     { 
      printf("ERROR - Could not allocate memory.\n"); 
      exit(0); 
     } 

     strcpy(BlackBox[i].firstName, firstName); 
     strcpy(BlackBox[i].lastName, lastName); 
     BlackBox[i].number = atol(number); 
    } 

    fclose(stream); 

    return BlackBox; 
} 


void SEARCH(struct _data *BlackBox, char **names, int lineCount, int inputs) 
{ 
    int i, l; 
    int found = 0; 

    printf("*******************************************\n"); 

    for (i = 0; i < inputs; ++i) 
    { 
     for (l = 0; l < lineCount; ++l) 
     { 
      if (BlackBox[l].firstName != NULL && !_stricmp(names[i], BlackBox[l].firstName) 
       || BlackBox[l].lastName != NULL && !_stricmp(names[i], BlackBox[l].lastName)) 
      { 
       printf("The name was found on line %d.\n", 1 + l); 
       found = 1; 
       break; 
      } 
     } 
     if (found) break; 
    } 

    if (!found) 
     printf("The name was NOT found.\n"); 

    printf("*******************************************\n"); 
} 

// FREE MEMORY 
void FREE(struct _data *BlackBox, int lineCount) 
{ 
    int i; 
    for (i = 0; i < lineCount; i++) 
    { 
     if (BlackBox[i].firstName != NULL) 
      free(BlackBox[i].firstName); 
     if (BlackBox[i].lastName != NULL) 
      free(BlackBox[i].lastName); 
    } 
    free(BlackBox); 
} 


// MAIN 
int main(int argc, char **argv) 
{ 
    int lineCount; 
    FILE *stream; 
    struct _data *BlackBox; 

    // argc == 1 WORKS, Below message is printed. 
    if (argc == 1) 
    { 
     printf("*******************************************\n"); 
     printf("* You must include a name to search for. *\n"); 
     printf("*******************************************\n"); 
    } 
    // argc == 2 DOES NOT WORK, Segmentation Fault.  
    if (argc > 1) 
    { 
     lineCount = SCAN(&stream); 
     if (lineCount > 0) 
     { 
      BlackBox = LOAD(stream, lineCount); 
      SEARCH(BlackBox, argv + 1, lineCount, argc - 1); 
      FREE(BlackBox, lineCount); 
     } 
    } 
    return 0; 
} 

Протестировано в командной строке, и оно работает.

-2

Проблема argv и argc. argc должен быть int (думаю, аргумент count), в то время как argv должен быть char**. Вы их перепутали в своем main.

+1

Это нетрадиционное, но это правильный код. Параметры 'main' не имеют специальных имен, вы можете называть их« donald »и« sean », если хотите –

+0

Я вижу, спасибо, что указали это. Несмотря на это, лучше соблюдать соглашения в таких случаях (особенно при использовании имен «argc» и «argv»). Это просто делает код более читаемым для других. – moosefoot

 Смежные вопросы

  • Нет связанных вопросов^_^