c - 删除冗余参数会导致段错误,似乎无缘无故

标签 c

以下程序查找并删除以相同字符开头和结尾的单词。它工作得很好,除了我决定从 deleteWords() 中获取用于打印结果文本的代码并将其放在 main() 中。因此,*fpOut 参数在deleteWords() 中变得多余。删除参数结果为

/bin/sh: line 1: 1371 Segmentation fault: 11 ./main duom.txt rez.txt make: *** [main] 错误 139

但是,如果我编译它并运行它的任何第三个参数(例如 int useless 参数而不是 FILE *fpOut),它可以正常工作。

有没有人知道是什么导致了这个问题?

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

    int checker (char zodis[]) {
        size_t last = strlen(zodis);
        if (zodis[0] == zodis[last-1])
            return 0;
        return 1;
    }

    void memAlloc (char **text, char **buffer, FILE **fp, char *fileName) {
        int fileLength;
        *fp = fopen(fileName, "r");
        fseek(*fp, 0L, SEEK_END);
        fileLength = fseek(*fp, 0L, SEEK_SET);
        *text = malloc(fileLength * sizeof(char));
        *buffer = malloc(fileLength * sizeof(char));
    }

    void deleteWords (FILE *fp, int anyUselessParameter, char *buffer) {
        char *text;
        while (fscanf(fp, "%s", text) == 1) {
            if (checker(text)) {
                printf("%s ", text);
                sprintf(buffer + strlen(buffer), "%s ", text);
            }
        }

        printf("\n");
    }

    int main(int argc, char *argv[]) {
        FILE *fp, *fpOut;
        int anyUselessParameter;
        char *text, *buffer, *inputFileName = argv[1], *outputFileName = argv[2];

        if (argc < 2)
            return 0;

        fpOut = fopen(outputFileName, "w");

        memAlloc(&text, &buffer, &fp, inputFileName);
        deleteWords(fp, anyUselessParameter, buffer);
        fputs(buffer, fpOut);

        fclose(fp);
        fclose(fpOut);
        free(text);
        return 0;
    }

最佳答案

char *text;
while (fscanf(fp, "%s", text) == 1) {

scanf 需要分配缓冲区。在这里它取消引用一个未初始化的指针 text 并写入它。 scanf 尝试写入 text[0]text[1].. 等等,因此访问文本越界和未定义行为发生。

*buffer = malloc(fileLength * sizeof(char));
...
sprintf(buffer + strlen(buffer), "%s ", text);

buffer 未初始化,因此 strlen(buffer) 将产生一些未定义的值。如果您希望稍后使用 strlen,请显式初始化 buffer[0] = '\0'。此外,您不包括用于在缓冲区内终止 '\0' 字符的内存。

当您尝试将文件读入缓冲区时,缓冲区是使用文件大小分配的

if (fread(buffer, fileLenght, 1, fp) != fileLength) { /* handle error */ }

如果必须,请使用 snprintf 而不是 sprintf 以确保安全。 snprinttf(buffer+strlen(buffer), fileLength - strlen(buffer), ...);

此外,如果没有在 %s 修饰符中指定字段长度,请尽量不要使用 scanf。你可以试试:

char text[256]; // or other maximum word length
while (fscanf(fp, "%255s", text) == 1) {

因为您已经为文件分配了内存,所以如果必须的话,您可以将它用作 scanf 的参数。需要为 scanf 准备格式字符串作为参数——这有点困难。见下文:

 for (;;) {
      // prepare scanf %s format modifier to use with printf to write to buffer end
      char fmt[20];
      size_t buffer_size = fileLenght;
      size_t free_in_buffer = buffer_size - strlen(buffer);
      snprintf(fmt, 20, "%%%ds", free_in_buffer);
      // we will write here: up to free_in_buffer
      char *in = buffer + strlen(buffer);
      if (fscanf(fp, fmt, in) != 1) break;
      // we now check the last readed word form the file
      if (!checker(in)) { 
         // if the last readed word is bad, we can revert it
         in[0] = '\0'
      }
  }

关于c - 删除冗余参数会导致段错误,似乎无缘无故,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53636538/

相关文章:

c - 为什么程序在 for 循环期间会在完成之前关闭?为什么我的呢?

C malloc + free 不断增加内存占用

c - 初级 C 数组和递增

objective-c - theos mobilesubstrate 调整中的 id 对象,我无法禁用此 -(id)

更改 Win32 窗口的像素

c - 尝试为服务器客户端程序中的每个连接初始化一个新结构,而不覆盖以前的结构

c++ - 如何根据我们调用程序的环境来初始化参数?

c - 链接 LAPACK/BLAS 库

c - 在编译时知道 for 循环的迭代次数是否有优势?

linux中链接器的对应选项