学习数据结构中一些C语言问题集锦2

本文探讨了C语言在处理数据结构时遇到的一些问题,包括输入字符串时遇到空格的处理、fflush与fgets的使用、strcmp函数的比较以及switch语句中enum类型的使用。还分析了内存布局和指针操作的细节,强调了深入理解C语言底层原理的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近重新查看数据结构,发现许多以前不懂,不清楚的问题。更加的意识到,以前学的C语言很基础,许多细节书本上都没讲解,看来下次得找本C语言进阶的书观摩了。
1.在输入字符串时,遇到输入字符串有空格时会出现空格后面字符串接收不到的问题,如:

char str1[20],str2[20];/*一般字符串建议用数组,用char *str有时会出问题*/  

scanf("%s",str1);  
scanf("%s",str2);  
printf("%s,%s",str1,str2);
若想输入"Holo is a wolf."给str1,"Super Sonic is beautiful."给str2,则只会输出"Holo,is",查阅MSDN知"Thescanf function reads data from the standard input streamstdin",scanf从stdin(以前学c是谭浩强的书,上面没讲)中读取数据,应该是以空格或者回车来当作接收的断点。想要接收包含空格的字符串,最好使用gets函数。代码如下:

char str1[20],str2[20];  
gets(str1);  
gets(str2);  
printf("%s,%s",str1,str2);  
但是gets函数一般不建议使用,它容易造成缓冲区溢出,经搜查,一般建议使用fgets函数。常用fgets(char *str,int n,stdin);来获取。如下:
char str1[5],str2[5];               /*内存较小,用啦测试会不会产生溢出*/  
fgets(str1,(sizeof(str1)-1),stdin);/*sizeof(str1)-1,fgets函数会自动在末尾添加一个'\0',所以一般内存建议设足够大。*/  
fflush(stdin);                     /*如果没有此句,如果输入超过数组内存,会直接赋值给下一个输入函数。造成错误。*/  
fgets(str2,(sizeof(str1)-1),stdin);/*当读满n-1个字符或者换行符时候,fgets函数会返回。应该添加一个去回车的函数.此处暂不考虑*/  
fflush(stdin);  
printf("%s%s",str1,str2);          /*输出会有换行符*/
关于前面提到的fflush函数,由于有时候输入数据长于缓存时,后面的输入会直接从流读入而不再接收用户输入经查找,需要用到此函数:
fflush(stdin)刷新标准输入缓冲区,把输入缓冲区里的东西丢弃 。
fflush(stdout)刷新标准输出缓冲区,把输出缓冲区里的东西打印到标准输出设备上。

一般在文件操作中建议使用fflush(stdout),flush即清空缓冲,在慢速设备上使用缓存是一种提升数据处理效率的手段,flush的作用是将内存中缓冲的内容实际写入外存媒介。fflush不应该在读取文件的时候用,而应该在写入文件的时候用。fflush会清空缓冲区,fclose在关闭文件之前也会清空缓冲区。如果使用exit函数退出程序,或者main函数返回,则所有打开后没有关闭的文件会自动关闭,关闭时也会清空缓冲区。


2.strcmp(a,b)要include <string.h>头文件,当两两字符串相等时返回0,a>b即从做往右a有大于b的AssicⅡ时,返回1,反之返回0.要小心使用
if(!strcmp(a,b))func();,对于一个数字a,它的非值为0.这个表示如果a,b相等,则执行func(),不等则不执行.对于在字符串数组中找某字符串有如下代码:

int i=0;
while(0!=strcmp(v,G.vexs[i]))i++;/*G.vexs表示图的顶点,在vexs里面找v,*/
if(i<G.vexnum)			 /*while只是用来确定所在位置。像这种确定字符串位置的*/
	return i;		 /*一般用这种方法较好,先用循环确定位置i*/
else{printf("Cannot find data %s!\n",v);exit(0);}

3.i++和++i,在需要他们返回数值的时候才有区别,i++是先返回i的值,再将i加1,++i则是先将i加1,再返回i的值,此用法在循环中我理解出错了,如循环

for(int i=0;i<5;++i);我认为第一次执行时是先将i+1,即等价于for(int i=1;i=<5;i++);其实不然,经汇编分析,括号内的是从左到右执行。其实在循环中,没有
用到i++或++i的返回值,此处他们等价。关于他们效率的问题,在编译器优化前,++i不需要零时变量效率高,但经编译器优化Release版本,实质是一样的。

参考网文,在有迭代器的时候,++i效率高些。关于迭代器暂时还未看,不过书中一般循环中用++i。反汇编代码自寻。


4.关于switch语句中遇见enum类型。在switch中有个规定,只能针对基本数据类型使用switch,这些类型包括int、char等。而在union输入enum时接收的是
字符串类型,需要将其化为enum类型。有时也需要将enum类型返回字符串类型。其代码如下

void strToenum(MGraph &G)/*将字符串转换成enum type   kind定义typedef enum{DG,DN}Kind; Kind kind;*/
{
	char str[10];
	scanf("%s",str);
	if(!strcmp(str,"DG"))G.kind=DG;
	else if(!strcmp(str,"DN"))G.kind=DN;
	else {printf("Error Typed!\n");exit(0);}
}

将枚举转换成字符串

typedef enum{Mon,Tus,Wen,Thr,Fri,Sta,Sun}Week;
char temp[7][4]={"Mon","Tus","Wen","Thr","Fri","Sta","Sun"};
printf("\n%s",temp[Mon]);/*用数组法就直接得出结果来了*/

5.关于编译器给存储在栈上变量分配存储空间时,谁在前面声明,就先给谁开辟空间。如:

char p[4],q[4];
36:       scanf("%s",p);
0040D418   lea         eax,[ebp-4]
0040D41B   push        eax
0040D41C   push        offset string "%s" (004223f4)
0040D421   call        scanf (0040f8f0)
0040D426   add         esp,8

39:       scanf("%s",q);
0040D43A   lea         edx,[ebp-8]
0040D43D   push        edx
0040D43E   push        offset string "%s" (004223f4)
0040D443   call        scanf (0040f8f0)
0040D448   add         esp,8
	char p[4],q[4];
	scanf("%s",p);
	scanf("%s",q);
	printf("%d,%d",p[0],q[0]);

(图中数字为10进制)堆栈在系统上如下图1:

图1     图2  

图3       图4

                                                                                                                                                                       

对于下面代码,如果输入"aaaa","bbbb",则会输出0,98本来是想输出p和q的第一个的AssicⅡ码,结果却不尽人意,原本要成为图2的,但是分析是scanf函数获得字符串会在后面默认加个‘\0’来表示字符串的末尾,本来q只申请了四个空间,此时会将'\0'填充到下面p的首部,便成了如上图3。在一个变量内,其值一般是按照从小位存低位,大位存高位(RISC架构)如上图4,1234存储方式。

	char p[4],q[4];
	a=3;
	b=4;
	scanf("%s",p);
	scanf("%s",q);
	printf("%d,%d",p[0],q[0]);

小注意:会发现如果上面的p[4]变成p[2]或者p[1]时,p的地址依然是ebp-4,q的地址是ebp-8说明对于数组大小小于4字节时默认分配4字节,当大与4字节时按具体大小分配。(可能一个指针占4字节所以默认分配4字节)。同时注意到如果只是定义一个char a;它也会分配4个字节的空间,难道是为了字节对齐?本机机器字长为32位4字节,一次能处理32位,则一字节申请32位空间吗?大概。ebp为本段程序的基址,一般只对它进行减法操作,来取得变量地址,是为了保护不是本段程序的变量吗,也大概。得参考深入的C语言书籍了。




其他一些后续问题还会添加,现在才觉得以前学的C语言根本不够用啊,好像学C语言不仅要从底层汇编理解,还要从编译器方向来考虑,有些还涉及到CPU的处理,如以前遇到的浮点数要初始化浮点数寄存器问题,是该找本好书系统学习了,求推荐orz

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值