大家好。我想知道为什么我用C编写的程序无法正常工作。我正在尝试从文本文件中读取整数并将其基于文本文件中整数的数量放入二维数组中。我想计算整数并在控制台上打印它们,以确保一切正常。我的代码可以在这里看到:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main()
{
FILE *fp;
fp = fopen("COSC450_P1_Data.txt", "r");
char str[200];
int words;
int row, columns, count;
if(fp == NULL)
{
printf("Could not open file %s", fp);
return 2;
}
while(getc(fp) != EOF)
{
count++;
fgets(str, 200, fp);
puts(str);
}
printf("%d ", count);
fclose(fp);
return 0;
}
这是文件的外观:
O123 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58
49 45 10 -57 20
57 39 20 58 23 10 20 58 -60 76 -82 28
28 -37 49 358 47 -50 37 29
57 -29 -20 47 69
93 57 23 49 -38 49 27 -40 48 39
56 -30 47 28 49
37 49
27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28
73 47 27 83 37 -29 40 37 49 20
17 -26 12 17 17
18 38 29 39 -118
19 10 20 58 -60 76 -82 28
28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38
49 30 -58 58 38
28 39
39 48 23 -50 28
48 29 39 40 29
下一张图片是输出的样子:
3 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58
49 45 10 -57 20
7 39 20 58 23 10 20 58 -60 76 -82 28
28 -37 49 358 47 -50 37 29
7 -29 -20 47 69
93 57 23 49 -38 49 27 -40 48 39
6 -30 47 28 49
7 49
27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28
3 47 27 83 37 -29 40 37 49 20
7 -26 12 17 17
8 38 29 39 -118
9 10 20 58 -60 76 -82 28
28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38
9 30 -58 58 38
8 39
9 48 23 -50 28
8 29 39 40 29
83
输出截断了某些数字,它给了我错误的整数总数。请帮忙。谢谢,祝你有美好的一天。
更新:谢谢您的帮助。不幸的是,将while循环while(getc(fp) != EOF)
更改为while(fgets(fp) != NULL)
会导致程序跳过第一行,如下所示:
49 45 10 -57 20 28 -37 49 358 47 -50 37 29 93 57 23 49 -38 49 27 -40 48 39
37 49
28 -37 49 -28 93 28
17 -26 12 17 17
19 10 20 58 -60 76 -82 28
28 -37 49 59 10 20 58 -60 76 -82 28
49 30 -58 58 38
39 48 23 -50 28
48 29 39 40 29 73
但是,从while循环的主体中删除fgets(str, 200, fp)
确实提供了更准确的输出,但不是我想要的:
23 34 -54 21 45 34 65 -54 21 45 34 65 -34 24 58
49 45 10 -57 20
57 39 20 58 23 10 20 58 -60 76 -82 28
28 -37 49 358 47 -50 37 29
57 -29 -20 47 69
93 57 23 49 -38 49 27 -40 48 39
56 -30 47 28 49
37 49
27 26 10 20 58 -60 26 10 20 58 -60 76 -82 28 28 -37 49 -28 93 28
73 47 27 83 37 -29 40 37 49 20
17 -26 12 17 17
18 38 29 39 -118
19 10 20 58 -60 76 -82 28
28 -37 49 59 10 58 -60 76 -82 28 28 -37 49 59 10 20 58 -60 76 -82 28 28 -37 49 30 -58 58 38 49 30 -58 58 38
49 30 -58 58 38
28 39
39 48 23 -50 28
48 29 39 40 29 83
如果您还有其他建议,请告诉我。再次谢谢大家。
答案 0 :(得分:2)
输出切断某些数字,它给了我错误的信息 整数总数。
当然可以。您正在使用以下命令从输入流中读取和删除字符:
while(getc(fp) != EOF)
...
,然后尝试读取整行数据,就好像什么都没有删除一样:
fgets(str, 200, fp);
fgets
会读取(并包括)尾随的'\n'
并将'\n'
包含在它填充的缓冲区中-因此,您实际上是在每行中砍掉第一个字符。
读取一次,按行转换所有值
最好将每个输入行读入缓冲区(尝试使用str
,然后使用strtol
(推荐)或sscanf
并保存偏移量)或更新后的指针以逐步通过缓冲区来挑选整数值。应该赞扬您使用fgets
的面向行的方法,这是正确的,因为您不能在删除每行的第一个字符之前叫它。
您还有其他注意事项。有效整数也可以以+/-
开头,因此您也需要考虑符号。 (除此之外,还有处理可能以o/O
或0x/0X
开头的八进制或十六进制值的问题)
使用strtol
strtol
用于处理缓冲区和转换找到的数值。 strtol
的原型为:
long int strtol(const char *nptr, char **endptr, int base);
其中nptr
是转换开始的指针,并且至关重要的是,endptr
将在数字成功转换后更新,以指向转换后最后一位数字后的 您可以在竞争验证后更新nptr = endptr;
来循环并转换下一个值。
与任何代码一样,验证是关键。对于strtol
,您必须检查nptr != endptr
以确定是否转换了任何数字。然后,您必须验证errno == 0
并由于转换错误(例如,值超出类型,溢出等范围)而未设置。
由于输入文件中整数值之间可能存在空格以外的字符,因此您只需从endptr
向前在缓冲区中扫描,直到找到下一个数字的有效起始字符(例如{{1} }和数字+/-
,请注意,如果要包含八进制值,则必须另外检查0-9
使用o/O
处理十进制和十六进制并仅输出转换后的值的简短示例是:
strtol
(注意:,如果您将值存储为#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lx\n",
ascii, val, val);
else
printf ("int conversion: %-10s % ld\n",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
,则由于存储类型({{1} })与转换类型(int
))
使用/输出示例
将数据文件放在INT_MIN <= val && val <= INT_MAX
中,只需将文件重定向到int
,您将得到以下输出:
long
总共找到160个整数。
使用integermess.txt
对于stdin
,您可以使用$ ./bin/fgets_strtol_any <debug/dat/integermess.txt
int conversion: 123 123
int conversion: 34 34
int conversion: -54 -54
int conversion: 21 21
int conversion: 45 45
int conversion: 34 34
int conversion: -54 -54
int conversion: 21 21
...
int conversion: 48 48
int conversion: 29 29
int conversion: 39 39
int conversion: 40 40
int conversion: 29 29
说明符来执行相同的操作,以确定数字转换所消耗的字符数,然后将其用于更新缓冲区中的位置以进行下一次转换。
从作为程序的第一个参数的文件名读取的示例(如果没有给定参数,则默认从sscanf
读取)仅处理十进制值的示例类似于:
sscanf
使用/输出示例
类似地使用"%n"
(输出格式略有不同),您将获得:
stdin
您还有其他选择。您可以使用#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
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;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('\n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("\n %d integers found.\n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
逐个字符读取数字文件,然后乘以sscanf
并加(或乘以$ ./bin/fgets_sscanf_int_any_ex <debug/dat/integermess.txt
123 34 -54 21 45 34 65 -54 21 45
34 65 -34 24 58 49 45 10 -57 20
57 39 20 58 23 10 20 58 -60 76
-82 28 28 -37 49 358 47 -50 37 29
57 -29 -20 47 69 93 57 23 49 -38
49 27 -40 48 39 56 -30 47 28 49
37 49 27 26 10 20 58 -60 26 10
20 58 -60 76 -82 28 28 -37 49 -28
93 28 73 47 27 83 37 -29 40 37
49 20 17 -26 12 17 17 18 38 29
39 -118 19 10 20 58 -60 76 -82 28
28 -37 49 59 10 58 -60 76 -82 28
28 -37 49 59 10 20 58 -60 76 -82
28 28 -37 49 30 -58 58 38 49 30
-58 58 38 49 30 -58 58 38 28 39
39 48 23 -50 28 48 29 39 40 29
160 integers found.
或fgetc
(对于八进制和 hex )。但是,比起您刚想到的函数,使用经过良好测试的库函数要好得多...
仔细检查一下,如果还有其他问题,请告诉我。您基本上是在正确的轨道上,只是还没有弄清楚转换,您正在砍掉每行的第一个字符。
答案 1 :(得分:0)
您可能希望将循环更改为:
while(!feof(fp))
将200更改为100。我认为每行200个字符有点太多。