簡體   English   中英

C程序分段錯誤main()

[英]C Program Segmentation Fault main()

我是C編程的新手,已經為需求規范編寫了代碼,但是我一直遇到Segmentation Fault並且無法繼續進行。 如果文件名為“ code.c”,並且運行時出現錯誤,則沒有傳遞參數(文件名)。 但是,如果傳遞了文件名,我們將進入“分段錯誤”。 任何幫助/建議,將不勝感激。

#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;
}

您在此代碼中有問題:

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

...

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

第二個strtok()調用應將NULL作為第一個參數傳遞。 strtok() ,第三個strtok()調用肯定會返回NULL因為第一個調用以這樣的方式修改了text ,使第二個調用消耗了整個內容(當從頭開始再次標記時,因為它錯誤地這樣做了)。 但是,您無需為此進行測試,結果atol()嘗試取消引用空指針。

更新

此外,正如@chqrlie和后來的@JamesWilkins所觀察到的那樣,您沒有為BlackBox[i].firstNameBlackBox[i].lastName分配足夠的空間,因為您還需要為字符串終止符BlackBox[i].lastName空間。 這是一個完全獨立的問題, 可能會產生一個段錯誤。 我喜歡@chqrlie的建議切換到strdup() ,但是將每個分配增加一個單位就足夠了。

更新2

此外,您對此行有疑問:

    getline(&text, &chrCount, stream);

您不會在第一次調用之前初始化變量text ,因此它包含垃圾值。 該函數僅在其第一個參數指向NULL指針時才分配緩沖區。 否則,它將行寫入通過解引用第一個參數獲得的指針所指向的緩沖區。 寫入內存中的隨機位置肯定會產生未定義的行為,實際上,這通常表現為段錯誤。

此外,除非您可以不依賴文件的行長於第一行,否則還需要在每次循環迭代結束時釋放text指針,並將其值重置為NULL ,以便getline()在下一次迭代。 如果您沒有在每次迭代中釋放它,那么您需要在循環結束后釋放它; 否則會泄漏內存。

試試這個(盡管我在Windows上使用Visual Studio)。 我添加了代碼以檢查最后一行是否缺少'\\ n',並且還允許使用可變數量的搜索字詞。 我還將字符串的內存分配增加了1,以說明空終止符。 我注意到您正在使用getline(const char*... ,我認為它是GNU(Linux?),所以我將其更改為fgets()只是為了可以在VS中進行編譯和測試(因此,如果為了安全起見,我也進行了各種null檢查。

#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;
}

在命令行上對其進行了測試,並且可以正常工作。

問題是argvargc argc應該是一個int(請考慮參數count ),而argv應該是char** 您將它們混在main

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM