简体   繁体   English

将 [^\n] 添加到 scanf_s 时,for 循环不起作用

[英]For loop doesn`t work when add [^\n] to a scanf_s

This program should ask you to add member (people) to a struct and print them on a file but after the first for loop just stop working and jump over the name part.该程序应该要求您将成员(人员)添加到结构中并将它们打印到文件上,但在第一个 for 循环之后停止工作并跳过名称部分。 I just found that thing that allow you to add space to a string, tried it but no success... I tried to remove it and it work without any problem so the [^\n] make something go wrong.我刚刚发现允许您向字符串添加空格的东西,尝试过但没有成功......我试图删除它并且它可以正常工作,所以[^\n]会出错。 What is wrong ?怎么了 ?

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

struct Staff {
    char Surname[100];
    char Name[100];
    int age;
    char spec[100];
    int id;
} person;

void write();
void leggi();
void trova();

int main() {
    write();
}

void write() {
    int i = 0;
    int n = 1;
    int r;

    FILE *fp;
    fopen_s(&fp, "index.txt", "w+");
    if (fp == NULL) {
        printf("Failed to open file\n");         
        exit(1);
    }

    fprintf(fp, "%d\n", i);

    for (i = 0; i < n; i++) {
        printf("Surame:\n");
        scanf_s("%[^\n]s", person.Surname, 100);
        fprintf(fp, "%s\t\t", person.Surname);
                                             //loop just get over the name part 
        printf("Name:\n");                   //after the first loop
        scanf_s("%s", person.Name, 100);               
        fprintf(fp, "%s\t", person.Name);

        printf("Age:\n");                  
        scanf_s("%d", &person.age);
        fprintf(fp, "%d\t", person.age);

        printf("Specialization\n");
        scanf_s("%s", person.spec, 100);
        fprintf(fp, "%s\n", person.spec);

        printf("Want to enter another? 1=yes  0=no...\n");
        scanf_s("%d", &r);
        if (r == 1)
            n = n + 1;
    }

    rewind(fp);
    fprintf(fp, "%d\n", i);    

    fclose(fp);
}

There are multiple problems in your code:您的代码中有多个问题:

  • you use the so called secure functions fopen_s , scanf_s etc, but you do not check the return values to detect invalid input.您使用所谓的安全函数fopen_sscanf_s等,但您不检查返回值以检测无效输入。 You should instead use standard functions, pass the appropriate arguments and check the return values.您应该改用标准函数,传递适当的参数并检查返回值。

  • using scanf_s is actually non portable: the scanf_s function defined in Annex K of the C Standard requires the length argument after the pointer to have size_t type, whereas the function with the same name in the Microsoft library uses type UINT , which has a different representation on 64-bit versions of their Windows OS.使用scanf_s实际上是不可移植的:C 标准附件 K 中定义的scanf_s函数要求指针后面的长度参数具有size_t类型,而 Microsoft 库中的同名函数使用类型UINT ,其表示形式不同在他们的 Windows 操作系统的 64 位版本上。 A classical case of the Embrace, enhance and extinguish strategy.拥抱、增强和消灭策略的经典案例。 In Standard C, one should write: scanf_s("%s", person.Name, (size_t)100) or better:在标准 C 中,应该写: scanf_s("%s", person.Name, (size_t)100)或更好:

    scanf_s("%s", person.Name, sizeof person.Name)

  • there is no need to open the output file for update with "w+" , just use "w" .无需使用"w+"打开输出文件进行更新,只需使用"w"即可。

  • you rewind the stream pointer back to the beginning of file and overwrite the number of entries at the start of the file.您将流指针倒回到文件的开头并覆盖文件开头的条目数。 This works as long as you have less than 10 entries, but beyond that, the number has more digits so some characters in the file will be corrupted.只要您的条目少于 10 个,此方法就有效,但除此之外,该数字有更多位数,因此文件中的某些字符将被损坏。 You could use a format with padding such as "%6d\n" which would allow for up to 1 million records without risks.您可以使用带有填充的格式,例如"%6d\n" ,这将允许最多 100 万条记录而没有风险。

  • "%[^\n]s" is not a correct scanf format: you should just write "%[^\n]" or better " %99[^\n]" to skip initial white space and limit the input to 99 characters. "%[^\n]s"不是正确的scanf格式:您应该只写"%[^\n]"或更好的" %99[^\n]"以跳过初始空白并将输入限制为 99人物。

Here is a modified version:这是修改后的版本:

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

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

struct Staff {
    char Surname[100];
    char Name[100];
    int age;
    char spec[100];
    int id;
};

void write(void);
void leggi(void);
void trova(void);

int main() {
    write();
}

int flush_input(void) {
    int c;
    while ((c = getchar()) != EOF && c != '\n')
        continue;
    return c;
}

void write(void) {
    int n = 0;
    int r;

    FILE *fp = fopen("index.txt", "w");
    if (fp == NULL) {
        fprintf("Failed to open file index.txt: %s\n",
                strerror(errno));
        exit(1);
    }

    fprintf(fp, "%6d\n", n);

    for (;;) {
        struct Staff person = { 0 };

        printf("Surname:\n");
        if (scanf(" %99[^\n]", person.Surname) != 1)
            break;
        flush_input();
        fprintf(fp, "%s\t\t", person.Surname);
                                             //loop just get over the name part 
        printf("Name:\n");                   //after the first loop
        scanf(" %99[^\n]", person.Name);               
        flush_input();
        fprintf(fp, "%s\t", person.Name);

        printf("Age:\n");                  
        scanf("%d", &person.age);
        flush_input();
        fprintf(fp, "%d\t", person.age);

        printf("Specialization\n");
        scanf(" %99[^\n]", person.spec, 100);
        flush_input();
        fprintf(fp, "%s\n", person.spec);
        n++;

        printf("Want to enter another? 1=yes  0=no...\n");
        if (scanf("%d", &r) != 1 || r != 1) {
            flush_input();
            break;
        }
        flush_input();
    }

    rewind(fp);
    // update the entry count on 6 characters
    fprintf(fp, "%6d\n", n);

    fclose(fp);
}

Change the call of scanf below for entering strings by inserting a space in the beginning of the format string.通过在格式字符串的开头插入空格来更改下面的 scanf 调用以输入字符串。 For example instead of this call例如,而不是这个电话

scanf_s("%[^\n]s", person.Surname, 100);

(where the letter s must be removed from the format string) write (其中字母s必须从格式字符串中删除)写

scanf_s(" %[^\n]", person.Surname, ( rsize_t )100);
        ^^^^^^^^

This allows to skip leading white space characters in the input buffer.这允许跳过输入缓冲区中的前导空白字符。

Pay attention to that changing the condition or the for loop the was as you are doing注意改变条件或 for 循环就像你正在做的那样

for (i = 0; i < n; i++) {
//...
    if (r == 1)
        n = n + 1;
}

makes the code unclear.使代码不清楚。 Instead of the for loop you could use do-while loop.代替 for 循环,您可以使用 do-while 循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM