[英]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个额外的内存字节,这会占用堆栈中的所有其他内容。 现在,可能只是碰巧一直在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);
当然,这不是唯一的解决方案。 而且已经不安全了。 但是我现在不想给您太多信息。 希望这是一个有益的开始。 小心点,好吗? =)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.