C:scanf和空格。我几乎尝试过所有事情,目前正在学习结构

时间:2017-08-05 21:52:12

标签: c whitespace scanf gets

我搜索了所有的网络,但我还没有找到真正的解决方案(也许我还没有用正确的搜索,我不知道)。 但是我们在这里:这是我的第一个带有结构的C项目,我尝试使用gets和puts来克服printf-scanf的白色空间问题,但是这会导致很多问题(程序被跳过)直接到看跌期权,没有获得)所以我进入了这个论坛的另一位客人的话题,其中提到了

scanf("%[^\n]",str);

我将此应用于我的代码,但我遇到了同样的问题,我也尝试了

scanf("%[^\n]s",str);
scanf("%[^\n]",&str); //despite looked senseless to me

我读过关于fgets和fscanf的内容,但我还处于早期阶段

以下是代码......我使用的是在Windows 10上运行的Visual Studio 2015。

#include <stdio.h>
#include <string.h>

typedef struct s_libro {
    char titolo[50];
    char autore[50];
    char editore[20];
    int pagine;
    int costo$;
}t_libro;

int main() {
    t_libro libro1;
    t_libro libro2;
    printf("Inserire autore(max 50) ,titolo(max 50) , editore(max 20), pagine, costo$\n");
    //LIBRO 1
    printf("\nLIBRO 1\n");

    printf("\nInserisci il nome dell'autore del libro1 : \n");
    scanf("%[^\n]", libro1.autore);

    printf("\nInserire titolo del libro1 : \n");
    scanf("%[^\n]", libro1.titolo);

    printf("\nInserire nome dell'editore del libro1:\n");
    scanf("%[^\n]", libro1.editore);

    printf("\nInserire numero di pagine del libro1 : \n");
    scanf("%d", &libro1.pagine);

    printf("\nInserire il costo (dato numerico) del libro1 : \n");
    scanf("%d", &libro1.costo$);

    printf("\nLIBRO1\t");
    printf("\nTitolo Libro1\t  %s", libro1.titolo);
    printf("\nAutore Libro1\t  %s", libro1.autore);
    printf("\nPagine Libro1\t  %d", libro1.pagine);
    printf("\nEditore Libro1\t  %s", libro1.editore);
    printf("\nCosto Libro1\t  %d $", libro1.costo$);

    printf("\n\n");


    //LIBRO 2

    printf("\nLIBRO 2\n");

    printf("\nInserisci il nome dell'autore del libro2 : ");
    scanf("%[^\n]", &libro2.autore);

    printf("\nInserire il titolo del libro2 : ");
    scanf("%[^\n]", &libro2.titolo);

    printf("\nInserire L'editore del libro2:");
    scanf("%[^\n]", libro2.editore);

    printf("\nInserire il numero di pagine del libro2 : ");
    scanf("%d", &libro2.pagine);

    printf("\nInserire il costo (dato numerico) del libro2 : ");
    scanf("%d", &libro2.costo$);

    printf("\nLIBRO2\t");
    printf("\nTitolo Libro2\t  %s", libro2.titolo);
    printf("\nAutore Libro2\t  %s", libro2.autore);
    printf("\nPagine Libro2\t  %d", libro2.pagine);
    printf("\nEditore Libro2\t  %s", libro2.editore);
    printf("\nCosto Libro2\t  %d $", libro2.costo$);

    printf("\n\n");
}

2 个答案:

答案 0 :(得分:2)

你有两个问题:

  1. 您不能检查scanf()是否成功。
  2. 您不允许scanf() leaves the newlines in the input stream
  3. 这一事实

    您的代码如下:

    printf("\nInserisci il nome dell'autore del libro1 : \n");
    scanf("%[^\n]", libro1.autore);
    
    printf("\nInserire titolo del libro1 : \n");
    scanf("%[^\n]", libro1.titolo);
    

    首先应该有效。第二个将失败,因为第一个在输入流中留下了一个换行符,并且扫描集不会将换行符识别为有效,因此它会失败。

    有几种可能的解决方案。哪个最好取决于您的详细要求。

    1. 使用标准C fgets()或POSIX getline()来读取行,然后使用sscanf() 处理数据。
    2. 在格式字符串中使用" %49[^\n]"以跳过包含换行符的空格,然后再将49个非换行符读入变量。这是最小的变化。长度限制可防止缓冲区溢出。是的,格式字符串中的大小不包括空字节。
    3. 使用scanf()读取每次输入后的行的残差。例如:

      static inline void gobble(void)
      {
          int c;
          while ((c = getchar()) != EOF && c != '\n')
              ;
      }
      

      然后:

      printf("\nInserisci il nome dell'autore del libro1 : \n");
      if (scanf("%49[^\n]", libro1.autore) != 1)
          …process error or EOF…
      gobble();
      
      printf("\nInserire titolo del libro1 : \n");
      if (scanf("%49[^\n]", libro1.titolo) != 1)
          …process error or EOF…
      gobble();
      
    4. 毫无疑问,还有很多其他选择;你必须决定什么最适合你。请注意,每次使用时都应检查scanf()的状态,而 应确保您不允许溢出。

      顺便提一下,scanf("%[^\n]", &str)变种是错误的。传递的参数类型为char (*)[50](如果变量为char str[50];),但扫描集转换规范需要char * - 一种完全不同的类型。有一个怪癖意味着你逃脱它; str&str的地址值相同,但类型不同,通过查看(str + 1)&str + 1可以看出 - 值会有很大差异。正确的表示法是scanf("%[^\n]", str),因此(模数添加溢出保护)。

答案 1 :(得分:1)

如果您想保留空格,我建议您使用fgets,然后删除任何尾随的新行字符,例如使用strcspn(由xing建议)。阅读项目将如下所示:

printf("\nInserisci il nome dell'autore del libro1 : \n");
fgets(libro1.autore,50,stdin);
libro1.autore[strcspn(libro1.autore,"\n")] = '\0';

如果用户输入许多字符,那么优点是您可以安全地处理缓冲区溢出问题&#34;请注意,有效名称最多包含48个字符(+新行字符+字符串终止字符)。并且 - 在用户的常规输入中 - 您可以安全地处理可能影响任何后续scanf("....")语句的新行字符。

请注意,scanf之类的scanf(" %[^\n]", libro1.autore)具有格式中的前导空格,不允许用户输入&#34;空&#34; name,因为格式中的空格将使用(仅)新行字符作为空格。没有前导空格的scanf,即scanf("%[^\n]", libro1.autore)不会消耗任何新行,从而导致您遇到的问题。

Conclusio:在这种情况下不要使用scanf