首页 > 解决方案 > 分段错误而不是显示消息 - 使用 c 中的指针从文件中读取

问题描述

我写了一个程序,它从文件中读取。我使用打印数组太大的条件,但是当我使用太大的数组而不是显示此消息时,我遇到了分段错误。

这是我的程序

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

#define N 10000 // Maximum array size

int _strlen(char *array) {
    int i;
    for (i = 0; array[i] != '\0'; ++i);    
    return i;
}

int readText(FILE *wp, char *s, int max) {
    int sum = 0;
    if (_strlen(s) > max) {
        printf("This array is too big. Maximum size is %d", max);
    } else {
        while ((*s++ = fgetc(wp)) != EOF) {
            sum++;
        }
        *(s-1) = '\0';
    }
    return sum;
}

int main(int argc, char *argv[]) {
    FILE *wz, *wc;                       
    char *s;
    char array[N];
    s = array;
    if (argc != 3) {                              
        printf("Wrong arguments number\n");
        printf("I should run this way:\n");
        printf("%s source result\n",argv[0]);
        exit(1);
    }

    if ((wz = fopen(argv[1], "r")) == NULL) {
        printf("Open error %s\n", argv[1]);
        exit(1);
    }
    if ((wc = fopen(argv[2], "w")) == NULL) {
        printf("Open error %s\n", argv[2]);
        exit(2);
    }

    fprintf(wc, "Read text from file source.txt");

    readText(wz, s, 10000);   

    return 0;
}

在输出中我想要:This array is too big. Maximum size is %d 而不是Segmentation fault core dumped

另外,我想说程序是当我使用较小的数组时,但是当他使用太大的数组而不是分段错误时,我想向用户显示正确的消息。

谢谢,我以这种方式改变了我的程序。唯一的问题是这个程序在每个 while 循环中检查 if 条件,所以这个程序可能很慢。

int readText(FILE *wp, char *s, int max) {
    int sum = 0;
    if (_strlen(s) > max) {
        printf("This array is too big. Maximum size is %d", max);
    } else {
        while ((*s++ = fgetc(wp)) != EOF) {
            sum++;
            if (sum > max) {
                printf("This array is too big. Maximum size is %d", max);
                break;
            }
        }
        *(s-1) = '\0';
    }
    return sum;
}

标签: carrayspointerscoredump

解决方案


评论/其他答案解决了您未定义的行为(在您的情况下是分段错误)。

唯一的问题是这个程序在每个 while 循环中检查 if 条件,所以这个程序可能很慢。

您的程序不是因为“如果”而变慢,而是因为您每个字符读取文件字符。

使用stat或等效函数,您可以获得文件的大小以读取它只抛出一个fread

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

#define N 10000 // Maximum array size

int main(int argc, char *argv[]) {
  char array[N];
  FILE *wz, *wc;                       
  struct stat st;
  off_t sz;

  if (argc != 3) {                              
    printf("Wrong arguments number\n"
           "I should run this way:\n"
           "%s source result\n", argv[0]);
    exit(1);
  }

  if ((wz = fopen(argv[1], "r")) == NULL) {
    printf("Cannot open %s to read : %s\n", argv[1], strerror(errno));
    exit(1);
  }

  if (stat(argv[1], &st) == -1) {
    printf("Cannot get stat of %s : %s\n", argv[1], strerror(errno));
    exit(1);
  }

  if (st.st_size > N-1) {
    printf("This array is too big. Maximum size is %d", N-1);
    sz = N-1;
  }
  else
    sz = st.st_size;

  if (fread(array, 1, sz, wz) != sz)  {
    printf("cannot read %s : %s", argv[1], strerror(errno));
    fclose(wz); /* for valgrind end test etc */
    exit(1);
  }
  array[sz] = 0;
  fclose(wz);

  if ((wc = fopen(argv[2], "w")) == NULL) {
    printf("Cannot open %s to write : %s\n", argv[2], strerror(errno));
    fclose(wz); /* for valgrind end test etc */
    exit(2);
  }

  /* ... */

  fclose(wc);

  return 0;
}

知道文件的大小可以消除对恒定大小的限制并尝试读取文件,同时您可以为以下内容分配足够的内存:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>

int main(int argc, char *argv[]) {
  char * array;
  FILE *wz, *wc;                       
  struct stat st;

  if (argc != 3) {                              
    printf("Wrong arguments number\n"
           "I should run this way:\n"
           "%s source result\n", argv[0]);
    exit(1);
  }

  if ((wz = fopen(argv[1], "r")) == NULL) {
    printf("Cannot open %s to read : %s\n", argv[1], strerror(errno));
    exit(1);
  }

  if (stat(argv[1], &st) == -1) {
    printf("Cannot get stat of %s : %s\n", argv[1], strerror(errno));
    exit(2);
  }

  if ((array = malloc(st.st_size + 1)) == NULL) {
    printf("Not enough memory to memorize the file %s\n", argv[1]);
    exit(3);
  }

  if (fread(array, 1, st.st_size, wz) != st.st_size)  {
    printf("cannot read %s : %s", argv[1], strerror(errno));
    fclose(wz); /* for valgrind end test etc */
    free(array); /* for valgrind etc */
    exit(4);
  }
  array[st.st_size] = 0;
  fclose(wz);

  if ((wc = fopen(argv[2], "w")) == NULL) {
    printf("Cannot open %s to write : %s\n", argv[2], strerror(errno));
    free(array); /* for valgrind etc */
    exit(5);
  }

  /* ... */

  fclose(wc);
  free(array); /* for valgrind etc */

  return 0;
}

无论如何,由于程序“源结果”的使用,您可能希望将argv[1]指定的文件复制到argv[2]指定的文件中,在这种情况下,最好逐块读写而不是全部读取以不使用大量内存并管理输入文件大小大于内存大小的情况。


推荐阅读