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

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

该程序应该要求您将成员(人员)添加到结构并将它们打印到文件中,但在第一个 for 循环之后停止工作并跳过名称部分。我刚刚发现允许您将 space 添加到字符串的东西,尝试过但没有成功...... 我试图删除它并且它可以正常工作,所以 [^\n] 出了点问题。 怎么了?

#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);
}

通过在格式字符串的开头插入 space 来更改下面用于输入字符串的 scanf 调用。例如,而不是这个调用

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

(其中字母 s 必须从格式字符串中删除)写

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

这允许跳过输入缓冲区中前导的白色 space 字符。

注意你正在做的改变条件或for循环

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

使代码不清楚。您可以使用 do-while 循环代替 for 循环。

您的代码中存在多个问题:

  • 你使用了所谓的secure函数fopen_sscanf_s等等,但是你没有检查return 值来检测无效输入。您应该改用标准函数,传递适当的参数并检查 return 值。

  • using scanf_s 实际上是不可移植的:C 标准附件 K 中定义的 scanf_s 函数要求指针后的长度参数具有 size_t类型,而 Microsoft 库中具有相同名称的函数使用类型 UINT,它在其 Windows OS 的 64 位版本上具有不同的表示形式。 Embrace, enhance and extinguish 策略的经典案例。在标准 C 中,应该写成:scanf_s("%s", person.Name, (size_t)100) 或更好:

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

  • 无需使用 "w+" 打开输出文件进行更新,只需使用 "w".

  • 您将流指针倒回文件开头并覆盖文件开头的条目数。只要您的条目少于 10 个,此方法就有效,但除此之外,该数字的位数更多,因此文件中的某些字符将被损坏。您可以使用带填充的格式,例如 "%6d\n",这样可以无风险地容纳多达 100 万条记录。

  • "%[^\n]s" 不是正确的 scanf 格式:您应该只写 "%[^\n]" 或更好的 " %99[^\n]" 以跳过初始白色 space 并将输入限制为 99 个字符。

这是修改后的版本:

#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);
}