C 将数据读取到文本文件并保留N个字符的de输出

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您是用两个空格保存名称,还是希望简化为只有一个空格?您是否必须管理其他

我希望从控制台读取数据并输出到文本文件,每个结构类型的变量保留N个字符。
文本文件类似于:

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;
    /* ... */
  }