- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我必须读取一个充满数字的文本文件,并将每个数字存储到一个字符串数组中,然后显示它。最终我想将数字转换为整数,但现在我只想将它们放入字符串数组中。我的程序只显示一半的数字以及一堆不需要的空行。这是我到目前为止所拥有的:
void displayArray (char *a, int j) {
for (int i = 0; i < j; i++) {
printf("%c\n", a[i]);
}
}
int main(int argc, const char *argv[]) {
char temp[3];
char str[26][3];
int i = 0;
// open file
FILE *fp;
fp = fopen("data.txt", "r");
// access file
while (!feof(fp)) {
fgets(temp, 26, fp);
//puts(temp);
strcpy(str[i], temp);
i++;
}
fclose(fp);
displayArray(str, 26);
return 0;
}
数据文件是:
8
2
0
10
.5
3
7
3
7
12
12
12
12
1
10
.5
12
12
12
12
7
3
7
3
最佳答案
您有两个主要问题,(1) str
中的列宽不足以容纳 1, 0,\n,\0
所需的 1, 0,\n,\0
10
。虽然您将读取 1, 0,\0
,但 '\n'
在输入流中将保持未读状态。要解决此问题,请增加列宽。
(永远不要吝啬缓冲区大小,如果您认为可以读取 3-4 个字符,请声明 8
左右的缓冲区)
其次,默认情况下,您无法删除读取并包含在 str[x]
中的尾随 '\n'
。 (所有面向行的函数,例如fgets
和POSIX getline
读取并包含'\n'
它们填充的缓冲区。修剪换行符很简单。获取长度,如果缓冲区中的最后一个字符是 '\n'
,则通过检查 str[n][length-1 来检查最后一个字符]
。如果是 '\n'
,则通过用 nul 终止 字符覆盖来删除它,例如
/* read each line up to MAXL lines */
while (n < MAXL && fgets (str[n], MAXC, fp)) {
size_t len = strlen (str[n]); /* get length */
long tmp; /* tmp value for conversion */
errno = 0; /* reset errno before each conversion */
if (len && str[n][len-1] == '\n') /* is last char '\n'? */
str[n][--len] = 0; /* overwrite with nul-char */
else { /* the string was too long, handle error */
fprintf (stderr, "error: value at line %d too long.\n", n);
return 1;
}
(注意:如果最后一个字符不是'\n'
,您还可以确认该行对于缓冲区来说是否太长)
接下来,您无法验证 fgets
的返回。读取可能会失败,您仍然尝试复制 temp
,例如(strcpy(str[i], temp);
)。您必须验证所有用户输入,否则您无法确信从那时起您不是在简单地处理垃圾。
您可以使用strtol
将字符串转换为long
。使用临时的 long
作为 strtol
的返回值,然后,在检查 errno
验证转换后,您可以验证返回的数字是否在在将其分配给整数数组之前的有效整数范围,例如
tmp = strtol (str[n], NULL, BASE); /* convert to long */
if (errno) { /* validate conversion */
fprintf (stderr, "error: conversion to int failed '%s'.\n",
str[n]);
return 1;
} /* validate in integer range */
if (tmp < INT_MIN || tmp > INT_MAX) {
fprintf (stderr, "error arr[%ld] exceeds range of int.\n",
tmp);
return 1;
}
arr[n++] = tmp; /* assign converted & validated value to array */
总而言之,您可以读取文件(或从 stdin
),将读取的值存储为字符串,并将字符串转换为整数值,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
enum { MAXC = 8, BASE = 10, MAXL = 26 };
int main (int argc, char **argv) {
int n = 0, /* array index */
arr[MAXL] = {0}; /* array of integers */
char str[MAXL][MAXC] = {""}; /* array of strings */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each line up to MAXL lines */
while (n < MAXL && fgets (str[n], MAXC, fp)) {
size_t len = strlen (str[n]); /* get length */
long tmp; /* tmp value for conversion */
errno = 0; /* reset errno before each */
if (len && str[n][len-1] == '\n') /* is last char '\n'? */
str[n][--len] = 0; /* overwrite with nul-char */
else { /* the string was too long, handle error */
fprintf (stderr, "error: value at line %d too long.\n", n);
return 1;
}
tmp = strtol (str[n], NULL, BASE); /* convert to long */
if (errno) { /* validate conversion */
fprintf (stderr, "error: conversion to int failed '%s'.\n",
str[n]);
return 1;
} /* validate in integer range */
if (tmp < INT_MIN || tmp > INT_MAX) {
fprintf (stderr, "error arr[%ld] exceeds range of int.\n",
tmp);
return 1;
}
arr[n++] = tmp; /* assign converted & validated value to array */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (int i = 0; i < n; i++) /* output both string and ints */
printf ("str[%2d] : %-3s arr[%2d] : %3d\n",
i, str[i], i, arr[i]);
return 0;
}
示例使用/输出
$ ./bin/cnvstrtoint < ../dat/numdata.txt
str[ 0] : 8 arr[ 0] : 8
str[ 1] : 2 arr[ 1] : 2
str[ 2] : 0 arr[ 2] : 0
str[ 3] : 10 arr[ 3] : 10
str[ 4] : .5 arr[ 4] : 0
str[ 5] : 3 arr[ 5] : 3
str[ 6] : 7 arr[ 6] : 7
str[ 7] : 3 arr[ 7] : 3
str[ 8] : 7 arr[ 8] : 7
str[ 9] : 12 arr[ 9] : 12
str[10] : 12 arr[10] : 12
str[11] : 12 arr[11] : 12
str[12] : 12 arr[12] : 12
str[13] : 1 arr[13] : 1
str[14] : 10 arr[14] : 10
str[15] : .5 arr[15] : 0
str[16] : 12 arr[16] : 12
str[17] : 12 arr[17] : 12
str[18] : 12 arr[18] : 12
str[19] : 12 arr[19] : 12
str[20] : 7 arr[20] : 7
str[21] : 3 arr[21] : 3
str[22] : 7 arr[22] : 7
str[23] : 3 arr[23] : 3
注意:上面.5
的整数转换结果为0
,所以如果需要存储浮点值,必须声明用于将转换后的值保存为 double
或 float
的数组,并使用 strtod
等浮点转换进行转换。
仔细检查一下,如果您还有其他问题,请告诉我。
<小时/>处理非长整型行
正如您所发现的,根据您的实现,strtol
可能不会接受并将 .5
截断为零,而是可能设置 错误号
。您可以灵活地以您选择的任何方式处理失败的转换。例如,如果您想在转换失败时手动分配 0
并使索引与读取的行数保持一致,则可以对失败的转换发出警告并手动分配0
,例如
if (errno) { /* validate conversion */
/* if you want to assing zero on a failed conversion, warn */
fprintf (stderr, "warning: conversion to int failed '%s' - "
"assigning 0.\n", str[n]);
tmp = 0;
}
(输出相同)
另一方面,如果您只是想跳过 strtol
未转换的任何值,您只需警告并继续
(该行已被 fgets 读取,继续前进到文件中的下一行):
if (errno) { /* validate conversion */
/* if you want to skip the value entirely, just continue */
fprintf (stderr, "warning: conversion to int failed '%s' - "
"skipping.\n", str[n]);
continue;
} /* validate in integer range */
示例使用/输出(跳过非长整数值
$ ./bin/cnvstrtoint < ../dat/numdata.txt
str[ 0] : 8 arr[ 0] : 8
str[ 1] : 2 arr[ 1] : 2
str[ 2] : 0 arr[ 2] : 0
str[ 3] : 10 arr[ 3] : 10
str[ 4] : 3 arr[ 4] : 3
str[ 5] : 7 arr[ 5] : 7
str[ 6] : 3 arr[ 6] : 3
str[ 7] : 7 arr[ 7] : 7
str[ 8] : 12 arr[ 8] : 12
str[ 9] : 12 arr[ 9] : 12
str[10] : 12 arr[10] : 12
str[11] : 12 arr[11] : 12
str[12] : 1 arr[12] : 1
str[13] : 10 arr[13] : 10
str[14] : 12 arr[14] : 12
str[15] : 12 arr[15] : 12
str[16] : 12 arr[16] : 12
str[17] : 12 arr[17] : 12
str[18] : 7 arr[18] : 7
str[19] : 3 arr[19] : 3
str[20] : 7 arr[20] : 7
str[21] : 3 arr[21] : 3
再看一遍,如果您还有其他问题,请告诉我。
关于c - 如何在C中逐行读取数字文本文件并将其存储到数组中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46985933/
我是一名优秀的程序员,十分优秀!