下面是我用来读取和打印struct数组值的代码 - 我在读取字符串时遇到错误:
#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;
答案 0 :(得分:2)
假设这是一个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个额外的字节内存,这会占用堆栈中的其他内容。现在可能只是发生成为add
和m
变量,现在这些变量具有巨大的价值。然后你写信给addr[add]
和BOOM - 你只是在堆栈之外的某处写入内存。
这是一个场景。真的,任何事情都可能发生。关键是这是未定义的行为,你应该不惜一切代价避免这种行为!
怎么办?好吧,到处都有关于此的大型主题,以及为什么scanf
BAD 首先读取字符串。但在紧要关头,我们假设您的用户表现得很好。如果您只是将这些指针更改为数组,生活将会改善:
/* 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);
当然,这不是唯一的解决方案。它已经不安全了。但是我不想在这一点上用太多的信息来压倒你。希望这是一个有用的开始。小心,好吗?! =)