分配错误分配

时间:2017-02-20 00:41:33

标签: c pointers segmentation-fault c-strings

我目前正在学习C,而我来自java。我们的任务要求我们从可以添加的文件中计算字符串,或者要求用户输入字符串。我们刚刚开始使用指针,我查找了分段错误发生的不同原因,但我不知道如何检查它是什么问题。我将我的所有指针初始化为NULL,但它仍然无法正常工作,而且从我读到的内容中,这是发生分段错误的最常见原因。

{{1}}

1 个答案:

答案 0 :(得分:1)

他们的代码存在一些问题:

  • 您已将string初始化为NULL,然后将其用作fgets()的输入缓冲区。 fgets()重新获得指向字符数组的指针,这些字符可以在堆栈上声明,也可以使用malloc(3)动态分配。您可以设置输入缓冲区,例如char string[100]
  • 必须选中
  • fgets(),因为当无法读取一行时它会返回NULL
  • strtok()的分隔符未计入\n附加的fgets()字符。您可以删除此换行符,也可以将其包含在分隔符中。如果要将其包含在分隔符中,请确保分隔符为" ,.-\n"
  • 您可以创建使用strtok()解析输入的函数,因为这样可以缩短main()的时间并减少代码中的重复性。示例函数原型可以是void longest_shortest_words(char line[], char **longest, char **shortest, size_t *word_count);,您可以通过指针将最长,最短的单词和单词数传递回main()。您还可以将最长和最短的单词存储在2D数组或指针数组中。
  • 您还应该明确检查您的文件是否已正确打开。应该包括这样的东西:

     infile = fopen("myfile.txt", "r");
     if (infile == NULL) {
         fprintf(stderr, "Failed to open file\n");
         exit(EXIT_FAILURE);
     }
    
  • 检查opt时,将?检查为switch语句中的字符是不对的。而不是:

    case '?':
        err = 1;
        break;
    

    使用default,其中包含输入的任何其他无效选项。以下是如何使用它:

    default:
        fprintf(stderr, "usage: %s [-l] [-s] [filename]\n", argv[0]);
        exit(EXIT_FAILURE);
    
  • 最后检查sflaglflag是不够的。您应该检查longWordshortWord是否不是NULL

以下是一些示例代码,用于演示以下几点:

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

#define LINESIZE 100

void longest_shortest_words(char line[], char **longest, char **shortest, size_t *wordcount);
void print_output(int lflag, int sflag, char *longword, char *shortword, size_t wordcount);
void remove_newline(char line[]);

int main(int argc, char * const argv[]) {
    FILE *infile;
    char line[LINESIZE] = {'\0'};
    int opt, sflag = 0, lflag = 0;
    size_t wordcount = 0;
    const char *optstr = "ls";
    char *longword = NULL, *shortword = NULL;

    while ((opt = getopt(argc, argv, optstr)) != -1) {
        switch(opt) {
            case 'l':
                lflag = 1;
                break;
            case 's':
                sflag = 1;
                break;
            default:
                fprintf(stderr, "usage: %s [-l] [-s] [filename]\n", argv[0]); 
                exit(EXIT_FAILURE);
        }
    }

    /* Checking if file is in directory */
    infile = fopen("myfile.txt", "r");
    if (infile == NULL) {
        fprintf(stderr, "Failed to open file\n");
        exit(EXIT_FAILURE);
    }

    /* checking if line exists in file */
    if (fgets(line, LINESIZE, infile) == NULL) {
        fprintf(stderr, "No line found in file.\n");

        printf("\nEnter string instead:\n");
        if (fgets(line, LINESIZE, stdin) != NULL) {
            remove_newline(line);
            longest_shortest_words(line, &longword, &shortword, &wordcount);   
            /* checking that longWord, shortWord and word_count are valid */
            if (longword != NULL && shortword != NULL && wordcount > 0) {
                print_output(lflag, sflag, longword, shortword, wordcount);
            }
        }

    /* file has line, do stuff with it */
    } else {
        remove_newline(line);
        longest_shortest_words(line, &longword, &shortword, &wordcount);
        print_output(lflag, sflag, longword, shortword, wordcount);
    }

    exit(EXIT_SUCCESS);
}

/* function for printing output, can be improved */
void print_output(int lflag, int sflag, char *longword, char *shortword, size_t wordcount) {
    if (lflag) {
        printf("Longest word: %s\n", longword);
    }

    if (sflag) {
        printf("Shortest word: %s\n", shortword);
    }

    if (wordcount > 0) {
        printf("Word count = %zu\n", wordcount);
    }
}

/* function for removing newline, and checking that input hasnt exceeded limit */
void remove_newline(char line[]) {
    size_t slen;

    slen = strlen(line);
    if (slen > 0 && line[slen-1] == '\n') {
        line[slen-1] = '\0';
    } else {
        fprintf(stderr, "\nToo many characters in input.\n");
        exit(EXIT_FAILURE);
    }
}

/* function which parses line, and saves longWord and shortWord in pointers */
void longest_shortest_words(char line[], char **longword, char **shortword, size_t *wordcount) {
    char *word = NULL;
    const char *delim = " ,.";

    word = strtok(line, delim);
    if (word != NULL) {
        *longword = word;
        *shortword = word;
        *wordcount = 1;
    }

    while ((word = strtok(NULL, delim)) != NULL) {
        (*wordcount)++;
        if (strlen(word) > strlen(*longword)) {
            *longword = word;
        } else if (strlen(word) < strlen(*shortword)) {
            *shortword = word;
        } 
    }
}

注意:上面显示的代码可以改进,只是为了向您展示解决问题的另一种方法。