我正在编写一个C程序,它将打开一个文件,对其进行写入,然后阅读所写内容。我可以打开,写入和关闭文件,但无法读取行并正确解析它们。
我已经阅读了许多其他博客和网站,但没有一个完全解决我正在尝试做的事情。我曾尝试调整他们的一般解决方案,但从未获得想要的行为。我已经使用fgets(),gets(),strtok()和scanf()和fscanf()运行了这段代码。我使用strtok_r()作为最佳实践被推荐。我用gets()和scanf()作为实验来观察它们的输出,而不是fgets()和fscanf()。
我想做什么:
有人可以告诉我我所缺少的是什么,什么功能将被视为最佳实践吗?
谢谢
我的代码:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(){
FILE * file;
// read data from customer.txt
char lines[30];
file = fopen("data.txt", "r");
// data.txt currently holds five lines
// 1 1 1 1 1
// 2 2 2 2 2
// 3 3 3 3 3
// 4 4 4 4 4
// 5 5 5 5 5
char *number;
char *next = lines;
int s = 0;
int t = 0;
int num;
int prams[30][30];
while(fgets(lines, 30, file)){
char *from = next;
while((number = strtok_r(from, " ", &next)) != NULL){
int i = atoi(number);
prams[t][s] = i;
printf("this is prams[%d][%d]: %d\n", t, s, prams[t][s]);
s++;
from = NULL;
}
t++;
}
fclose(file);
}// main
预期输出:
这是婴儿车[0] [0]:1
...
这是婴儿车[4] [4]:5
实际输出:
这是婴儿车[0] [0]:1
这是婴儿车[0] [1]:1
这是婴儿车[0] [2]:1
这是婴儿车[0] [3]:1
这是婴儿车[0] [4]:1
程序结束
答案 0 :(得分:1)
直接的主要问题是,您不断告诉strtok_r()
从字符串的开头开始,因此它继续返回相同的值。您需要将第一个参数strtok_r()
设置为NULL,以便它从上次中断的地方继续:
char *from = next;
while ((number = strtok_r(from, " ", &next)) != NULL)
{
int i = atoi(number);
prams[t][s] = i;
printf("this is prams[%d][%d]: %d\n", t, s, prams[t][s]);
s++;
from = NULL;
}
有些人主张strtol()
胜过atoi()
;他们方面有一些正义,但可能不足以解决问题。
有关如何使用sscanf()解析行的信息,另请参见How to use sscanf()
in loops?。
使用:
while (fgets(lines, 30, file))
用于外循环控制; don't use feof()
除外(也许)在循环终止之后(以区分EOF和I / O错误)。 (几年前,我检查了我的数百个C源文件,发现eof()
的使用少于一半,全部用于错误检查代码,而没有用于循环控件。您实际上不需要经常使用它。)
答案 1 :(得分:1)
主要问题是:
strtok_r
,仅在第一次解析行时(编辑之前),第一个参数不能为null number = strtok_r(from, " ", &next)
下一步被strtok_r
修改,同时用于初始化下一行的 from ,因此第二行不会被正确读取,您的执行情况仅仅是:这是婴儿车[0] [0]:11
这是婴儿车[0] [1]:12
这是婴儿车[0] [2]:13
这是婴儿车[0] [3]:14
这是婴儿车[0] [4]:15
这是婴儿车[3] [5]:0
包含 data.txt 的
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
51 52 53 54 55
(还要查看索引[3][5]
,因为您错过了重置 s 的时间)
其他说明:
考虑到这些注意事项的建议是(我将数组初始化为0,而不假设每行的数字数量):
#include <stdio.h>
#include <string.h>
#define LINELENGTH 30
#define SIZE 30
int main(){
// read data from customer.txt
char lines[LINELENGTH];
FILE * file = fopen("data.txt", "r");
if (file == NULL) {
fprintf(stderr, "cannot read data.txt");
return -1;
}
// data.txt currently holds five lines
// 1 1 1 1 1
// 2 2 2 2 2
// 3 3 3 3 3
// 4 4 4 4 4
// 5 5 5 5 5
int t = 0;
int prams[SIZE][SIZE] = { 0 };
while (fgets(lines, LINELENGTH, file)) {
char * number;
char * str = lines;
int s = 0;
while ((number = strtok(str, " \n")) != NULL) {
char c;
int i;
if (sscanf(number, "%d%c", &i, &c) != 1) {
fprintf(stderr, "invalid number '%s'\n", number);
return -1;
}
prams[t][s] = i;
printf("this is prams[%d][%d]: %d\n", t, s, prams[t][s]);
str = NULL;
if (++s == SIZE)
break;
}
if (++t == SIZE)
break;
}
fclose(file);
}// main
我使用sscanf(number, "%d%c", &i, &c) != 1
来轻松检测数字是否只有数字,请注意,我添加的\n
是 strtok
编译和执行:
pi@raspberrypi:/tmp $ !g
gcc -pedantic -Wall -Wextra l.c
pi@raspberrypi:/tmp $ cat data.txt
11 12 13 14 15
21 22 23 24 25
31 32 33 34 35
41 42 43 44 45
51 52 53 54 55
pi@raspberrypi:/tmp $ ./a.out
this is prams[0][0]: 11
this is prams[0][1]: 12
this is prams[0][2]: 13
this is prams[0][3]: 14
this is prams[0][4]: 15
this is prams[1][0]: 21
this is prams[1][1]: 22
this is prams[1][2]: 23
this is prams[1][3]: 24
this is prams[1][4]: 25
this is prams[2][0]: 31
this is prams[2][1]: 32
this is prams[2][2]: 33
this is prams[2][3]: 34
this is prams[2][4]: 35
this is prams[3][0]: 41
this is prams[3][1]: 42
this is prams[3][2]: 43
this is prams[3][3]: 44
this is prams[3][4]: 45
this is prams[4][0]: 51
this is prams[4][1]: 52
this is prams[4][2]: 53
this is prams[4][3]: 54
this is prams[4][4]: 55
答案 2 :(得分:0)
如果您想解析以空格分隔的文本,那么scanf和好友是您的最佳选择。但是,如果要特别将换行符而不是空格对待,则需要fgets + sscanf循环:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="addServicesRequest.php" method="POST">
<div class="container form-control">
<h5>Ajoutez des services à votre réservation :</h5>
<div class="text-center">
<input type="checkbox" name="service" value="10">
<label>service</label>
<strong class="priceOfService">10 €</strong><br>
</div>
<div class="text-center">
<input type="checkbox" name="service" value="20">
<label>service</label>
<strong class="priceOfService">20 €</strong><br>
</div>
<hr>
<div>
<p>Prix de la réservation : <strong>X€</strong>
Prix des services : <strong id="priceServices">X€</strong></p>
<h4>Total : <strong id="totalPrices">X€</strong></h4>
<input type="button" value="Valider" class="btn btn-dark btn-sm container">
</div>
</div>
</form>
注意还请检查边界以确保不超过固定大小的数组边界。