C语言 指针小记

来源:互联网 发布:ipad 软件不能上网 编辑:程序博客网 时间:2024/06/06 03:00

最近重新拾起C语言,打算过一遍C Primer Plus的课后题,今天在第11章第10题时有点卡壳,犯了几个错误。在此记录一下,顺便梳理下指针的知识。

题目:

编写一个程序,读取输入,直到读入了10个字符串或遇到EOF,由二者中最先被满足的那个终止读取过程。这个程序可以为用户提供一个有5个选项的菜单:输出初始字符串列表、按ASCII顺序输出字符串、按长度递增顺序输出字符串、按字符串中第一个单词的长度输出字符串和退出。菜单可以循环,直到用户输入退出请求。当然,程序要能真正完成菜单中的各项功能。


解答:

初读题目,框架应该是首先读入几个字符串,然后输入一个菜单选项,根据输入的选项,执行相应操作。很自然的想到switch()语句。

先贴出来自己做错的函数:

#include <stdio.h>int main(void){char ch;int t;int  ct1,ct2;char *temp;int i,j;char str[10][81];char *p[10];int n = 0;puts("Input string:");while( n<10  && gets(str[n])){puts("Input string:");n++;}p = str;puts("1:输出字符串");puts("2:按 ASCII 顺序输出");puts("3:按长度递增");puts("4:按第一个单词的长度");puts("0:推出");while(getchar(ch)){while(getchar()!='\n')continue;switch(ch){case '1':break;case '2':for(i=0;i<n;i++)for(j=i+1;j<n;j++){if(strcmp(str[i],str[j])>0){temp = *str[i];*str[i] = *str[j];*str[j] = temp;}}break;case '3':for(i=0;i<n;i++)for(j=i+1;j<n;j++){if(strlen(str[i])>strlen(str[j])){temp = p[i];p[i] = p[j];p[j] = temp;}}break;case '4':for(i=0;i<n;i++)for(j=i+1;j<n;j++){while(*str[i]!=' ')ct1++;while(*str[j]!= ' ')ct2++;if(ct1>ct2){temp = *str[i];*str[i] = *str[j];*str[j] = temp;}}break;case '0':puts("Bye!");return 0;default:puts("Please input ");break;}for (i=0;i<n;i++)puts(p[i]); }}
编译无所通过。提示
错误3error C2106: “=”: 左操作数必须为左值d:\program files (x86)\microsoft visual studio 9.0\project\11-10\11-10\10.c2011-10

这个错误的原因是对字符串数组以及指针理解不清。错误的认为str和p都是首地址,通过把str赋给p,然p指向str。但这里p是一个包含10个指针的数组,重点是数组。虽然数组的名字和指针一样,都是数组首地址,但是数组名是常量,不可以改变。

改正的方法:p是一个有10个指针的数组,也就是说p[n]是指针,而指针是变量,因此可以这样改:

while( n<10  && gets(str[n])){p[n] = str[n];puts("Input string:");n++;}
再次编译,通过,运行,1没有问题,但是选2的时候仍然是按数序输入。通过调试发现,在switch()语句中,没有任何以个和输入的1相匹配,之后做如下修改:

while(scanf("%d",&c))

编译、运行,结果错误,每个字符串只改变了首个字符。问题出在*str[i]只代表第一个元素的值。做如下修改:

case 2:for(i=0;i<n;i++)for(j=i+1;j<n;j++){if(strcmp(str[i],str[j])>0){temp = p[i];p[i] = p[j];p[j] = temp;}}break;


编译、运行,1.2都能得到正确结果,但3仍然按原顺序给出。此处犯的错误依旧是对指针理解不透彻。我们通过
while( n<10  && gets(str[n])){p[n] = str[n];puts("Input string:");n++;}
使数组p中储存的每个指针依次指向str,也就是说p中每个元素储存的都是对应str的地址。错误的认为,改变p中元素的地址,str也相应改变了。这里用错了一个概念,也就是,虽然*p[n]和str[n]指向相同的位置,但是改变p[n],并不能改变*p[n]指向的值,改变的只是p[n]中储存的地址的值。

此处直接改变str[n]的值是不对的,如问题1一样,str是一个二维数组,str[n]是一个一位数组,她是一个常量。

关于这个问题的解决办法,考虑了两个错误的,一个是让*str[n] = *p[n],但问题是,这只改变了首元素的值;第二个是想用strcpy(str[n],p[n]),存在的问题是可能导致数据溢出。所以最简单的方法就是输出p。

经过接近一天的时间,终于把这个函数实现了,虽然程序不完美,但是能运行出结果。过程收获很多。

最终代码:

#include <stdio.h>int main(void){int c;int t;int  ct1=0;int  ct2=0;char *temp;int i,j;char str[10][81];char *p[10];int n = 0;puts("Input string:");while( n<10  && gets(str[n])){p[n] = str[n];puts("Input string:");n++;}puts("1:输出字符串");puts("2:按 ASCII 顺序输出");puts("3:按长度递增");puts("4:按第一个单词的长度");puts("0:推出");while(scanf("%d",&c)){while(getchar()!='\n')continue;switch(c){case 1:break;case 2:for(i=0;i<n;i++)for(j=i+1;j<n;j++){if(strcmp(str[i],str[j])>0){temp = p[i];p[i] = p[j];p[j] = temp;}}break;case 3:for(i=0;i<n;i++)for(j=i+1;j<n;j++){if(strlen(str[i])>strlen(str[j])){temp = p[i];p[i] = p[j];p[j] = temp;}}break;case 4:for(i=0;i<n;i++)for(j=i+1;j<n;j++){while(*(str[i]+ct1)!=' ' && *(str[i]+ct1)!='\0')ct1++;while(*(str[j]+ct2)!= ' '&& *(str[j]+ct2)!='\0')ct2++;if(ct1>ct2){temp = p[i];p[i] = p[j];p[j] = temp;}ct1 = 0;ct2 = 0;}break;case 0:puts("Bye!");return 0;default:puts("Please input right");break;}for (i=0;i<n;i++)puts(p[i]); }}









原创粉丝点击