C分段错误(输入文件名,读取文件)

时间:2014-06-26 21:57:12

标签: c file-io

我正在处理ACM代码挑战,我需要从用户指定的文件中读取。我到目前为止的代码:


int main(){

    // Input file name

    char filename[80];
    printf("\nInput file name: ");
    fgets(filename, 79, stdin);

    // Read from file

    FILE *data_file;
    data_file = fopen(filename,"r");

    char data[1000];

    for(int i=0; i<1000; i++){
        fscanf(data_file, "%1d", &data[i]);
    }

    fclose(data_file);

    return 0;
}

然而,有一个错误:'分段错误'。使用一些printf语句,我知道文件名已被正确读取。


运行Ubuntu 14.04 LTS; IDE是Code :: Blocks。

3 个答案:

答案 0 :(得分:3)

这里有很多错误。最重要的是,您没有检查fopen的结果是否成功,这意味着您将尝试在无效的文件句柄上调用fscanf,从而导致您的段错误。

另一个原因是你没有修剪\n在文件名缓冲区中跟踪fgets字符之前离开的尾随换行符NULL。这意味着你几乎肯定不会成功地超越这条线。

第三,你的fscanf调用没有检查错误条件(即:文件结束),所以它会尝试读出界限并引入错误。

最后,您的代码中使用了许多硬编码的标记值。如果编译器支持VLA和C99标准,则应使用宏或const int值替换它们。

示例代码


#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#ifndef PATH_MAX
#define  PATH_MAX    (1024)
#endif

#define BUF_LEN_MAX  (1024)

int main() {
    /* Declare variables */
    int i;
    bool err = false;
    char filename[PATH_MAX];
    char data[BUF_LEN_MAX];
    FILE *data_file;

    /* Get input file name */
    printf("\nInput file name: ");
    fgets(filename, PATH_MAX, stdin);
    strtok(filename, "\n");   /* Trim trailing newline character left behind by fgets */
    printf("Data file to use:%s\n", filename);

    // Read from file
    if ((data_file = fopen(filename,"r")) == NULL) {
       printf("File could not be found or opened; Aborting\n");
       return 1;
    }
    /* Print out the gathered data one character at a time for verification */
    for (i=0; i<PATH_MAX && !err; i++) {
       if (fscanf(data_file, "%c", &data[i]) == EOF) {
          err = true;
       }
       printf("Character #%04d - '%c'\n", i, data[i]);
    }
    fclose(data_file);

    return 0;
}

示例测试文件 - tmp.txt


total 32
drwxr-xr-x   4 admin   darkstar   136B Jun 26 15:00 ./
drwxr-xr-x@ 62 admin   darkstar   2.1K Jun 26 13:38 ../
-rw-r--r--@  1 admin   darkstar    12K May 13 05:52 .DS_Store
-rw-r--r--   1 admin   darkstar     0B Jun 26 15:00 tmp.txt

样本运行 - 故意失败测试


Input file name: someone
Data file to use:someone
File could not be found or opened; Aborting

样本运行 - 测试2 - 成功


Input file name: tmp.txt
Data file to use:tmp.txt
Character #0000 - 't'
Character #0001 - 'o'
Character #0002 - 't'
Character #0003 - 'a'
Character #0004 - 'l'
Character #0005 - ' '
Character #0006 - '3'
Character #0007 - '2'
Character #0008 - '
'
Character #0009 - 'd'
Character #0010 - 'r'
Character #0011 - 'w'
Character #0012 - 'x'
Character #0013 - 'r'
Character #0014 - '-'
Character #0015 - 'x'
Character #0016 - 'r'
Character #0017 - '-'
Character #0018 - 'x'
Character #0019 - ' '
Character #0020 - ' '
Character #0021 - ' '
Character #0022 - '4'
Character #0023 - ' '
Character #0024 - 'a'
Character #0025 - 'd'
Character #0026 - 'm'
Character #0027 - 'i'
Character #0028 - 'n'
Character #0029 - ' '
Character #0030 - ' '
Character #0031 - ' '
Character #0032 - 'd'
Character #0033 - 'a'
Character #0034 - 'r'
Character #0035 - 'k'
Character #0036 - 's'
Character #0037 - 't'
Character #0038 - 'a'
Character #0039 - 'r'
Character #0040 - ' '
Character #0041 - ' '
Character #0042 - ' '
Character #0043 - '1'
Character #0044 - '3'
Character #0045 - '6'
Character #0046 - 'B'
Character #0047 - ' '
Character #0048 - 'J'
Character #0049 - 'u'
Character #0050 - 'n'
Character #0051 - ' '
Character #0052 - '2'
Character #0053 - '6'
Character #0054 - ' '
Character #0055 - '1'
Character #0056 - '5'
Character #0057 - ':'
Character #0058 - '0'
Character #0059 - '0'
Character #0060 - ' '
Character #0061 - '.'
Character #0062 - '/'
Character #0063 - '
'
Character #0064 - 'd'
Character #0065 - 'r'
Character #0066 - 'w'
Character #0067 - 'x'
Character #0068 - 'r'
Character #0069 - '-'
Character #0070 - 'x'
Character #0071 - 'r'
Character #0072 - '-'
Character #0073 - 'x'
Character #0074 - '@'
Character #0075 - ' '
Character #0076 - '6'
Character #0077 - '2'
Character #0078 - ' '
Character #0079 - 'a'
Character #0080 - 'd'
Character #0081 - 'm'
Character #0082 - 'i'
Character #0083 - 'n'
Character #0084 - ' '
Character #0085 - ' '
Character #0086 - ' '
Character #0087 - 'd'
Character #0088 - 'a'
Character #0089 - 'r'
Character #0090 - 'k'
Character #0091 - 's'
Character #0092 - 't'
Character #0093 - 'a'
Character #0094 - 'r'
Character #0095 - ' '
Character #0096 - ' '
Character #0097 - ' '
Character #0098 - '2'
Character #0099 - '.'
Character #0100 - '1'
Character #0101 - 'K'
Character #0102 - ' '
Character #0103 - 'J'
Character #0104 - 'u'
Character #0105 - 'n'
Character #0106 - ' '
Character #0107 - '2'
Character #0108 - '6'
Character #0109 - ' '
Character #0110 - '1'
Character #0111 - '3'
Character #0112 - ':'
Character #0113 - '3'
Character #0114 - '8'
Character #0115 - ' '
Character #0116 - '.'
Character #0117 - '.'
Character #0118 - '/'
Character #0119 - '
'
Character #0120 - '-'
Character #0121 - 'r'
Character #0122 - 'w'
Character #0123 - '-'
Character #0124 - 'r'
Character #0125 - '-'
Character #0126 - '-'
Character #0127 - 'r'
Character #0128 - '-'
Character #0129 - '-'
Character #0130 - '@'
Character #0131 - ' '
Character #0132 - ' '
Character #0133 - '1'
Character #0134 - ' '
Character #0135 - 'a'
Character #0136 - 'd'
Character #0137 - 'm'
Character #0138 - 'i'
Character #0139 - 'n'
Character #0140 - ' '
Character #0141 - ' '
Character #0142 - ' '
Character #0143 - 'd'
Character #0144 - 'a'
Character #0145 - 'r'
Character #0146 - 'k'
Character #0147 - 's'
Character #0148 - 't'
Character #0149 - 'a'
Character #0150 - 'r'
Character #0151 - ' '
Character #0152 - ' '
Character #0153 - ' '
Character #0154 - ' '
Character #0155 - '1'
Character #0156 - '2'
Character #0157 - 'K'
Character #0158 - ' '
Character #0159 - 'M'
Character #0160 - 'a'
Character #0161 - 'y'
Character #0162 - ' '
Character #0163 - '1'
Character #0164 - '3'
Character #0165 - ' '
Character #0166 - '0'
Character #0167 - '5'
Character #0168 - ':'
Character #0169 - '5'
Character #0170 - '2'
Character #0171 - ' '
Character #0172 - '.'
Character #0173 - 'D'
Character #0174 - 'S'
Character #0175 - '_'
Character #0176 - 'S'
Character #0177 - 't'
Character #0178 - 'o'
Character #0179 - 'r'
Character #0180 - 'e'
Character #0181 - '
'
Character #0182 - '-'
Character #0183 - 'r'
Character #0184 - 'w'
Character #0185 - '-'
Character #0186 - 'r'
Character #0187 - '-'
Character #0188 - '-'
Character #0189 - 'r'
Character #0190 - '-'
Character #0191 - '-'
Character #0192 - ' '
Character #0193 - ' '
Character #0194 - ' '
Character #0195 - '1'
Character #0196 - ' '
Character #0197 - 'a'
Character #0198 - 'd'
Character #0199 - 'm'
Character #0200 - 'i'
Character #0201 - 'n'
Character #0202 - ' '
Character #0203 - ' '
Character #0204 - ' '
Character #0205 - 'd'
Character #0206 - 'a'
Character #0207 - 'r'
Character #0208 - 'k'
Character #0209 - 's'
Character #0210 - 't'
Character #0211 - 'a'
Character #0212 - 'r'
Character #0213 - ' '
Character #0214 - ' '
Character #0215 - ' '
Character #0216 - ' '
Character #0217 - ' '
Character #0218 - '0'
Character #0219 - 'B'
Character #0220 - ' '
Character #0221 - 'J'
Character #0222 - 'u'
Character #0223 - 'n'
Character #0224 - ' '
Character #0225 - '2'
Character #0226 - '6'
Character #0227 - ' '
Character #0228 - '1'
Character #0229 - '5'
Character #0230 - ':'
Character #0231 - '0'
Character #0232 - '0'
Character #0233 - ' '
Character #0234 - 't'
Character #0235 - 'm'
Character #0236 - 'p'
Character #0237 - '.'
Character #0238 - 't'
Character #0239 - 'x'
Character #0240 - 't'
Character #0241 - '
'
Character #0242 - ''

<强>参考


  1. 从fgets()输入中删除尾随换行符,已访问2014-06-27,<https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input>

答案 1 :(得分:1)

字符串:filename,填充后在NULL之前有一个0x0A:

enter image description here

或者,以另一种方式显示:

enter image description here

这导致fopen()处的文件未找到错误。此时,您的代码应退出。超出这一点将导致未定义的行为。

这可能不是您唯一的错误,但为了解决此错误,您可以执行以下操作:

(从stdin填充文件名后) 你必须把它清理一下......

int len = strlen(filename);
filename[len-2]=0;  

其他错误 位于此部分代码中:

char data[1000];  //You have created char data type

for(int i=0; i<1000; i++){
    fscanf(data_file, "%1d", &data[i]);//but your format string "%1d" expects an int.
}

<强> 要么 更改fscanf(data_file, "%1d", &data[i]);
fscanf(data_file, "%s", data[i]);

或者创建一个int数组:

int data[1000];

并使用原始的fscanf()调用。

顺便说一下,你应该检查fopen()&amp;的输出值。 fscanf()表示预期结果,如果发生则处理异常。

答案 2 :(得分:0)

你应该写这样的东西。您始终需要检查是否可以打开该文件。最好只传入命令行上的路径并将其从argv中拉出来。

int main(){
char filename[80];
FILE *data_file;
char data[1000];
int i;

/* Input file name */
printf("\nInput file name: ");
fgets(filename, 79, stdin);

/* Remove '/n' from filename string*/
if (filename && strlen(filename) > 1) {
   filename[strlen(filename)-2] = 0;
 }

/* Open file */
data_file = fopen(filename,"r");

/* Read data */
if (data_file) {
   for (i=0; i<1000; i++){
      fscanf(data_file, "%1d", &data[i]);
      }
  fclose(data_file);
  }
else {
    printf("Could not open file\n");
    }
return 0;
}