C 将数据读取到文本文件并保留N个字符的de输出
我希望从控制台读取数据并输出到文本文件,每个结构类型的变量保留N个字符。C 将数据读取到文本文件并保留N个字符的de输出,c,file,struct,scanf,C,File,Struct,Scanf,我希望从控制台读取数据并输出到文本文件,每个结构类型的变量保留N个字符。 文本文件类似于: 1 111 1 Peter 22 22 2 John Lays 3 3 3 Anne Belgs 正如您在问题中所说,您不能使用scanf读取包含空格的复杂名称 但在搜索如何做之前,需要决定做什么 可能您不想记住开头和结尾的额外空格(包括换行符),并且可能名称不能为空 但是在一个复杂的名字里面呢?如果用户输入John Lays您是用两个空格保存名称,还是希望简化为只有一个空格?您是否必须管理其他
文本文件类似于: 1 111 1 Peter 22 22 2 John Lays 3 3 3 Anne Belgs
正如您在问题中所说,您不能使用scanf读取包含空格的复杂名称 但在搜索如何做之前,需要决定做什么 可能您不想记住开头和结尾的额外空格(包括换行符),并且可能名称不能为空 但是在一个复杂的名字里面呢?如果用户输入
John Lays
您是用两个空格保存名称,还是希望简化为只有一个空格?您是否必须管理其他特殊字符,如“-”(是John-Lays
/John-Lays
/John-Lays
读作John-Lays
?)
如果输入字符串超过10个字符,该怎么办?只是停下来阅读,让其他人继续阅读,还是绕开换行?因为您在每次输入之前打印一条消息,所以很明显,您希望每行都有一条输入,并且必须绕过该行的其余部分
如果您不想按原样读取字符串,那么最好的方法可能是编写自己的读取字符串函数
如果用户没有为ID或Potentia或Avariado输入数字,您还必须决定该怎么做,目前您甚至没有检测到错误,这不是一个好方法。那么在这种情况下,您是中止所有(退出程序),还是重做读取?可能您更喜欢再次阅读,因为您需要绕过无效输入,但这意味着什么,要绕过所有内容直到换行
例如:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* read an int memorizing its value in v,
return 0 in case of EOF else a non null value */
int readInt(const char * msg, int * v)
{
for (;;) {
fputs(msg, stdout);
if (scanf("%d", v) == 1)
return 1;
/* not a number or EOF, bypass all up to \n */
int c;
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
return 0;
puts("invalid value"); /* message may be also get in argument */
}
}
/* read a string up to a \n
remove extra spaces at the beginning and end
simplify internal multiple spaces
accept any character and do not manage in a special way characters like like '-'
a non empty string must be read
read at most sz-1 characters in s then place the null character (as fgets), sz must be > 1
if the line too long bypass the rest of the input up to \n
return 0 in case of EOF else a non null value */
int readStr(const char * msg, char * s, size_t sz)
{
fputs(msg, stdout);
/* read the first char bypassing spaces including \n */
if (scanf(" %c", s) == 0)
// EOF
return 0;
size_t index = 1;
int c;
sz -= 1;
while (index != sz) {
c = fgetc(stdin);
if ((c == EOF) || (c == '\n'))
break;
if (!isspace(c))
s[index++] = c;
else if (s[index - 1] != ' ')
s[index++] = ' ';
}
s[(s[index - 1] != ' ') ? index : index-1] = 0;
// bypass possible rest of the line
while ((c != EOF) && (c != '\n'))
c = fgetc(stdin);
return 1;
}
/* ******************* */
struct estruturaCarro {
int id, potencia, avariado;
char name[11];
} carro;
int main()
{
do {
if (!readInt("\n ID......:", &carro.id) ||
!readInt("\n Potencia:", &carro.potencia) ||
!readInt("\n Avariado:", &carro.avariado) ||
!readStr("\n NAME:", carro.name, sizeof(carro.name))) {
puts("EOF");
return -1;
}
else
printf("%-2d %-3d %-1d '%-10s' \n\n", carro.id, carro.potencia, carro.avariado, carro.name);
} while (strcmp(carro.name, "end"));
return 0;
}
当您读取文件并假设它是通过执行fprintf(fp,%-2d%-3d%-1d%-10s“,…)生成的时,
:
请注意,如果名称长度小于10个字符,则名称的末尾有空格
或者,您也可以使用类似于上一个stdin的方式进行阅读。当您使用
scanf
读取名称时,您成功地读取了包含空格的“单词”。为您的fscanf
调用考虑这一点。另外,这样做的标准方法是在fgets
返回非空指针时循环,然后使用sscanf
进行解析。不要使用feof,检查fscanf返回值。谢谢(“obrigado”),Bruno.如果google trans是正确的,你说我将发布另一个1帮助请求,这次是关于文件的动态结构-对我来说这是一个bug我已经接受了这个评论…!;-)对不起,我只会说法语和英语
#include <stdio.h>
#include <string.h>
#include <ctype.h>
/* read an int memorizing its value in v,
return 0 in case of EOF else a non null value */
int readInt(const char * msg, int * v)
{
for (;;) {
fputs(msg, stdout);
if (scanf("%d", v) == 1)
return 1;
/* not a number or EOF, bypass all up to \n */
int c;
while ((c = fgetc(stdin)) != '\n')
if (c == EOF)
return 0;
puts("invalid value"); /* message may be also get in argument */
}
}
/* read a string up to a \n
remove extra spaces at the beginning and end
simplify internal multiple spaces
accept any character and do not manage in a special way characters like like '-'
a non empty string must be read
read at most sz-1 characters in s then place the null character (as fgets), sz must be > 1
if the line too long bypass the rest of the input up to \n
return 0 in case of EOF else a non null value */
int readStr(const char * msg, char * s, size_t sz)
{
fputs(msg, stdout);
/* read the first char bypassing spaces including \n */
if (scanf(" %c", s) == 0)
// EOF
return 0;
size_t index = 1;
int c;
sz -= 1;
while (index != sz) {
c = fgetc(stdin);
if ((c == EOF) || (c == '\n'))
break;
if (!isspace(c))
s[index++] = c;
else if (s[index - 1] != ' ')
s[index++] = ' ';
}
s[(s[index - 1] != ' ') ? index : index-1] = 0;
// bypass possible rest of the line
while ((c != EOF) && (c != '\n'))
c = fgetc(stdin);
return 1;
}
/* ******************* */
struct estruturaCarro {
int id, potencia, avariado;
char name[11];
} carro;
int main()
{
do {
if (!readInt("\n ID......:", &carro.id) ||
!readInt("\n Potencia:", &carro.potencia) ||
!readInt("\n Avariado:", &carro.avariado) ||
!readStr("\n NAME:", carro.name, sizeof(carro.name))) {
puts("EOF");
return -1;
}
else
printf("%-2d %-3d %-1d '%-10s' \n\n", carro.id, carro.potencia, carro.avariado, carro.name);
} while (strcmp(carro.name, "end"));
return 0;
}
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall r.c
pi@raspberrypi:/tmp $ ./a.out
ID......:aze
invalid value
ID......:qsd
invalid value
ID......:1
Potencia:2
Avariado:3
NAME:aze u iiiiiiiiiiiiiiiiii
1 2 3 'aze u iiii'
ID......:11
Potencia:22
Avariado:0
NAME: end
11 22 0 'end '
pi@raspberrypi:/tmp $
char line[21]; /* each line has 20 characters newline included */
while (fgets(line, sizeof(line), fp) != NULL) {
if (sscanf(line, "%d %d %d", &carro.id, &carro.potencia, &carro.avariado) != 3)
/* abnormal case, invalid file */
break; /* anything else you want to do */
/* the string starts at the index 9 and has 10 characters out of the newline */
memcpy(carro.name, line + 9, 10);
carro.name[10] = 0;
/* ... */
}