繁体   English   中英

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

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

该程序应该要求您将成员(人员)添加到结构中并将它们打印到文件上,但在第一个 for 循环之后停止工作并跳过名称部分。 我刚刚发现允许您向字符串添加空格的东西,尝试过但没有成功......我试图删除它并且它可以正常工作,所以[^\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);
}

您的代码中有多个问题:

  • 您使用所谓的安全函数fopen_sscanf_s等,但您不检查返回值以检测无效输入。 您应该改用标准函数,传递适当的参数并检查返回值。

  • 使用scanf_s实际上是不可移植的:C 标准附件 K 中定义的scanf_s函数要求指针后面的长度参数具有size_t类型,而 Microsoft 库中的同名函数使用类型UINT ,其表示形式不同在他们的 Windows 操作系统的 64 位版本上。 拥抱、增强和消灭策略的经典案例。 在标准 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]"以跳过初始空白并将输入限制为 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);
}

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

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

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

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

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

注意改变条件或 for 循环就像你正在做的那样

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

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

暂无
暂无

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

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