繁体   English   中英

scanf字符串-C语言

[英]scanf string - c language

以下是我用于读取和打印结构数组值的代码-读取字符串时出现错误:

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

struct addressbook{
    char *fname;
    char *lname;
    char *num;
    char *email;
};

int main() {
    struct addressbook addr[100];
    int add=0,m=0;
    while (m<3)
    {
        printf("1. Show All Entries\n");
        printf("2. Add Entry\n");
        printf("3. Quit\n");
        scanf("%d",&m);
        if (m==1)
        {
            int i;
            for (i=0; i<add;i++)
            {
                printf("FName: %s , LName: %s , Number: %s ,  Email: %s \n",&addr[i].fname, &addr[i].lname,&addr[i].num,&addr[i].email);
            }
        }
        else if (m==2)
        {
            if (add<101)
            {
                struct addressbook a;
                printf("Enter First Name: ");
                scanf(" %s", &a.fname);
                printf("Enter last Name: ");
                scanf(" %s", &a.lname);
                printf("Enter Contact Number: ");
                scanf(" %s", &a.num);
                printf("Enter Email: ");
                scanf(" %s", &a.email);
                addr[add] = a;
                add=add+1;
            }
            else{printf("100 limit reached");}

        }
        else if (m=3)
        {
            m=3;
        }
        else
        {
            m=0;
            printf("Invalid option");
        }
    }
}

这是一个基本程序-但是由于未知错误而被关闭。 在此处输入图片说明

如果输入的字符串长度只有3个字符,则没有错误。 你能纠正我哪里出错了。

尝试了以下代码,但仍然无法正常工作

printf("Enter First Name: ");
                scanf(" %s", &addr[add].fname);
                printf("Enter last Name: ");
                scanf(" %s", &addr[add].lname);
                printf("Enter Contact Number: ");
                scanf(" %s", &addr[add].num);
                printf("Enter Email: ");
                scanf(" %s", &addr[add].email);
                add=add+1;

假设这是一个32位系统,那么指针每个为4个字节。 您的addressbook结构在内存中看起来像这样:

    0 1 2 3 4 5 6 7 8 9 A B C D E F
   ---------------------------------
    [fname ][lname ][num   ][email ]

当您声明局部变量struct addressbook a; ,这正是您在堆栈上得到的-16个字节的未初始化内存:

    0 1 2 3 4 5 6 7 8 9 A B C D E F
   ---------------------------------
    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

现在,您开始使用scanf读取指针的实际值。 这是您的结构在第一次输入后的样子:

    0 1 2 3 4 5 6 7  8 9 A B C D E F
   ----------------------------------
    a s d a s d a \0 ? ? ? ? ? ? ? ?

在最后一次输入之后:

    0 1 2 3 4 5 6 7 8 9 A B C D E F * * * * * *
   ---------------------------------------------
    a s d a c a s c 1 2 3 1 a s d a s d a s d \0

哎呦! 因此,您在结构末尾写了6个额外的内存字节,这会占用堆栈中的所有其他内容。 现在,可能只是碰巧一直在addm变量,这是现在一些巨大的价值。 然后,您写入addr[add]和BOOM -您只是在堆栈之外的某个地方写入了内存。

那是一种情况。 真的会发生任何事情。 关键是这是未定义的行为 ,您应该不惜一切代价避免这种情况!

该怎么办? 好吧,到处都有关于此的大型主题,以及为什么scanf是读取字符串的对象。 但是,让我们假设您的用户表现得很正常。 如果仅更改这些指向数组的指针,则生活会有所改善:

/* Arbitrary string length limits */
#define MAX_FNAME 20
#define MAX_LNAME 20
#define MAX_NUM 20
#define MAX_EMAIL 50

struct addressbook{
    char fname[MAX_FNAME];
    char lname[MAX_LNAME];
    char num[MAX_NUM];
    char email[MAX_EMAIL];
};

现在,您确保在调用scanf时使用的指针正确。 如果使用a.fname ,则编译器会将数组衰减为指针,因此您不应传递&a.fname 您可以编写a.fname&a.fname[0]

scanf(" %s", a.fname);

当然,这不是唯一的解决方案。 而且已经不安全了。 但是我现在不想给您太多信息。 希望这是一个有益的开始。 小心点,好吗? =)

暂无
暂无

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

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