scanfstring-c语言

scanfstring-c语言,c,scanf,C,Scanf,下面是我用来读取和打印结构数组值的代码-读取字符串时出错: #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

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

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

让我们假设这是一个32位系统,因此指针每个是4个字节。您的
地址簿
结构在内存中如下所示:

    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个字节的内存,这会消耗堆栈中的任何其他内容。现在可能正好是
add
m
变量,它们现在是一些巨大的值。然后你写到
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);

当然,这不是唯一的解决方案。而且已经不安全了。但我不想在这一点上用太多的信息压倒你。希望这是一个有益的开始。小心点,好吗

scanf(“%s”和a.fname);没有正确初始化任何结构字段。事实上,它们根本没有草签。因此,您不能在
scanf
中使用它们
scanf
不会为您分配内存。您需要为其提供有效的缓冲区进行写入。这是未定义的行为。您没有为这些指针分配内存。更糟糕的是,你实际上并不是在向它们指向的内存中写入字符串,而是在向实际指针中写入字符串,这本身与错误无关,你可能需要注意这样的错误:
,否则如果(m=3)
-这实际上是一个始终为真的赋值。我将m=3修改为m==3-但其余部分不清楚,我试着从我的角度来解决这个问题,我已经习惯了VB.net,但c似乎太难了:(这是一个很好的解释。需要学习很多东西-VB比这简单得多:(不用担心,VB可能更简单,但是没有人用VB实现操作系统、设备驱动程序或严肃编译器。习惯于在C中小心。开始思考程序如何在CPU上执行任务。如果你想要一种更具表现力和同样强大的语言,你可以学习C++。但是现在,慢慢来。熟悉C语言的这种新的神奇功能吧。你很快就会意识到它踢了VB的屁股。
scanf(" %s", a.fname);