C语言指针经典练习题

1、指针,字符数组

若定义

  1. char s[2][3]={“ab”, “cd”}, *p=(char *)s;

那么下列表达式语法正确,并且其值与 s[1][1]相等的表达式(并非一定与其等价)是

 

A. *(s+3)

 

B. p[1][1]

C. *(p+3)

D. *++P+2

答案:D

分析:这道题很好。首先字符型指针p存放的是字符串s的首地址,而字符串s表示的是这样一个字符串:

ab_

cd_

为了便于理解,“_”表示空格,即没有元素。题中s[1][1]是d,所以要在ABCD中寻找表示s[1][1]的数。

先来看*(s+3),s表示数组首地址,不是指针型变量,所以s+3没有意义。p[1][1]同样由于p是指针,不存在这种表达。*(p+3)是是p表示的指针后移3位,因此*(p+3)是c。D选项有点复杂,*++p+2 这个比较有趣,p是一个char*指针,指向字符数组首地址,&s[0][0]。首先++的优先级更高执行++p得到的是&s[0][1],然后*运算符解引用,得到s[0][1],s[0][1]的字符是'b',然后'b'+2,得到的就是'd'的ASCII码. 

下面是一道类似的题目:

 

若定义 char a[3][3]={“ad”, “ce” , “fb”}, *s = (char *)a; 那么下列表达式语法正确,并且其值与 a[2][1]相等的表达式是_______。

  A.*(a+3) B.*(*a+5) C.s[2][1] D.*++s-2

答案是D,分析可参照:https://blog.csdn.net/zhanshen112/article/details/80786576

 

18、指针的指针 

有函数原型为

  1. void f(intint *);

,主函数中有变量定义:

  1. int a=2, *p=&a;

则下列函数调用正确的是

  • A. f(a,&p);
  • B. f(*p, p);
  • C. f(p,a);
  • D. f(*p, a);
  • 答案:B
  • 分析:注意p为指向整型的指针,*p则指向内存地址处所存放的数据。*p实际上就是a.

 

22、宏定义

下列程序段的输出是_______。

#define DF(a,b)  (a+2*b) 
int s=5;
int k= DF(s+1,s-3);
printf("%d",k);

答案:13

分析:k=DF(5+1,5-3)=5+1+2*5-3=13。注意宏定义中参数的传递,k=DF(5+1,5-3)=(5+1)+2*(5-3)=10是错误的。

23、全局变量、局部变量、静态变量的生存期

以下代码的输出是:

int x, y, z, w;
void p(int *y, int x)
{
    static int w;
    *y++; x++; w = x+*--y;
    printf("%d#%d#%d#%d#",x,*y,z,w);
}
int main(void)
{
    int x, y, z, w;
    x=y=z=w=1;
    do{
        static int x;
        p(&x, y);
        printf("%d#%d#%d#%d#",x,y,z,w);
    } while(0);
    return 0;
}

答案:2#0#0#2#0#1#1#1#

 

解析:主要考察局部变量和全局变量的生存期,以及静态本地变量。注释后的代码如下:

int x, y, z, w;    //这里是全局变量,定义在任何函数的外面,若不初始化赋值,则均为0;。注意,主函数里面的变量仍为局部变量
void p(int *y, int x)    //p函数接收整型指针变量和整型变量的输入,返回值为空
{
    static int w;    //定义静态变量w,若不初始化赋值,则w==0;
    *y++; x++; w = x+*--y;
    printf("%d#%d#%d#%d#",x,*y,z,w);
}
int main(void)
{
    int x, y, z, w;
    x=y=z=w=1;
    do{
        static int x;
        p(&x, y);
        printf("%d#%d#%d#%d#",x,y,z,w);
    } while(0);
    return 0;
}

从主函数进行分析,主函数内部定义了四个int型变量,若不进行初始化,则全为0。主函数内部定义完之后就进行了初始化,均初始化为1,所以在do-while内部,可以看到由于只定义了静态局部变量x,而且没有初始化赋值,则静态局部变量x为0,y,z,w均仍为1。所以

 printf("%d#%d#%d#%d#",x,y,z,w);

的输出是0#1#1#1#。

再来分析p这个函数:

void p(int *y, int x)    //p函数接收整型指针变量和整型变量的输入,返回值为空
{
    static int w;    //定义静态变量w,若不初始化赋值,则w==0;
    *y++; x++; w = x+*--y;
    printf("%d#%d#%d#%d#",x,*y,z,w);
}

首先p函数无返回值,接受两个输入:int型指针变量、int型变量。p函数内部同样定义了一个静态局部变量w,但是w后面有赋值的语句

w = x+*--y;

*y++和x++是两个关键,首先*和++,--运算符处于同一优先级,结合方向是自右向左。因此*y++可以看做是*(y++),但是由于y++是先执行y,跳出去与*结合,再让y++。所以*y++实际上等效于先执行*y操作,再执行y++。由于y是指针,因此y++是指针所指内存地址的向后移动,移动的大小是一个sizeof(int)。x++同理先执行x(由于没有任何操作,x不变),再让x+1,这里实际上由于x没有任何操作,x++相当于只执行了x+1,由于局部变量传入p函数的x为1,这里x就等于2了。

由于y是指针变量,因此*y表示取出指针所指内存地址的值。由于传进去的

 

 static int x;
        p(&x, y);

 

x是静态变量,则x=0,因此*y=0。这里要注意p的原型是void p(int *y, int x)  ,而使用p函数时,传进去的是

 

  p(&x, y);

顺序不要搞反了。w=x+*--y,这里等价于w=x+*(--y),由于在上面的*y++,y已经执行了y+1,这里(--y)先执行--,再执行y,即先执行y-1,再把y-1的结果传出去。注意这里的-1指的是减去一个int型变量的内存大小。因此y还是原来的内存位置。所以*y还是取出原来指针指向内存地址的值,即还是原来的静态局部变量x,值为0。因此w=x+*--y中x=2,(*--y)等于0,所以w=2。由于p函数里的z只能那个接受全局变量,因此z=0,所以p函数执行之后打印:2#0#0#2。

 

24、sizeof和数组

假设sizeof(int)的值为4,对数组定义:

 

  1. int a[3][6];

则sizeof(a[0])的值为____.

答案:24

解析:a[0]里面有a[0][0],a[0][1]……a[0][5],共6个元素,均为int,因此4*6=24.

 

25、条件表达式以及&&,||,!

写出表示“当 x 的取值在 [-10, 0]  的范围内,结果为真,否则为假”的C语言表达式,注意不要任何空格

答案:x>=-10&&x<=0 或 x<=0&&x>=-10 或 !(x<-10||x>0)

解析:我的答案是(x>=-10)&&(x<=0)?1:0,不如参考答案。

 

26、&&,||,!

若 int a = 6, b = 0, c = 3,则表达式 a && b || b - c的结果是(以1表示真,0表示假)

答案:1

 

27、指针、字符串和数组

以下代码段的输出是:

char a[20]="cehiknqtw";
char *s="fbla",*p;
int i, j;
for(p=s; *p; p++) {
   j=0;
   while (*p>=a[j] && a[j]!='\0') j++;
   for(i=strlen(a); i>=j; i--) a[i+1] = a[i];
   a[j]=*p;
}
printf("%s", a);

答案:abcefhiklnqtw

分析:这段代码具有一定的难度。首先a[20]是一个字符数组,s,p是字符型指针。s刚开始是“fbla”的首地址,因此*s实际上是指向f的内存地址的值,即s存放的是f的地址。

核心部分是for循环中的语句,

p=s; *p; p++

是将s的指针赋给p,然后逐渐后移,也就是把s字符串中的字符指针逐渐都进行赋值。即,p会逐渐等于f,b,l,a的地址。

 while (*p>=a[j] && a[j]!='\0') j++;

这个语句的意义是在a[]中寻求大于*p所指的字符,当*p==f时,a[]中的h是大于f的,此时j==2,程序跳出while循环,进入内层for循环,内层for循环的意义是把j==2之后的字符都进行后移一位,为*p==f腾出位置,然后将a[2]=*p,也就是把s中的第一个字符填入a[]中。下面依次填入s中其他的字符,因此这个程序完成的任务实际上是把s中的字符按照字符间ASCII数值的大小关系填入a[]中。

 

28、宏定义

根据下面的定义,F0(3+4)的输出结果是_______(注意没有空格)

#define  F1(var)  printf("var=%d", var)
#define  F0(var)  F1(var * var)

答案:var=19

 

29、指针的指针

程序T1的代码如下,则运行T1  abc  bcd  cde  aed的输出结果是_______.

int main(int argc, char** argv)
{
    while(**argv++!='a');
    printf("%s", *argv);
    return 0;
}

答案:bcd

分析:

解释一:程序进来后,argv的内容是 T1 abc bcd cde aed

while(); 注意while循环后面有分号,说明printf是在循环之后才执行的。

**argv++相当于

  1. return argv;

  2. return **argv

  3. argv++ (每执行一次,将会指向下一个字符串)

当执行第二次循环时, abc,此时**argv为'a',循环结束。在此之后,argv++指向了下一个字符串,也就是bcd。

解释二:

1、int main(int argc, char** argv)表示当执行程序时可以带上参数,所以题目中执行时就写为T1  abc  bcd  cde  aed,可理解为要执行一个名为T1的程序,并需要对abc  bcd  cde  aed这几个字符串进行处理

2、argc表示参数的个数,此处argc=5,即T1  abc  bcd  cde  aed这5个

3、argv表示的是命令行参数,char** argv可以看成char* argv[],即一个字符串数组,每个元素对应一个字符串,值为字符串的首地址。因此**argv就是字符串的首字母

4、**argv++!='a'就表示当字符串的首字母不等于a时,则跳过该字符串,继续判定下个字符串。一旦发现某个字符串首字母为a,则在argv++作用下输出下一个字符串。比如检测第一个字符串abc时发现首字母为a,则跳出while循环,并在argv++作用下输出bcd

5、**argv++优先级可以看成**(argv++)

以下是一些测试(我的文件名是Cpp1.exe,不影响),就可以看出规律了

补充:**的用法

 

*表示指针,**表示指针的指针。

例如:int *a;这个语句声明了一个变量a,a的数据类型是int *,也就是整型变量的指针类型(如果不懂什么是指针,那这个问题就没有意义了)。也就是说 a的值是一个内存地址,在这个地址所在的内存空间中存放的是一个整型变量。再看:int **b;这个语句也声明了一个变量b,b的数据类型是int **,也就是整型变量的指针的指针类型(二级指针)。也就是说 b的值是一个内存地址,该地址所在的内存空间中存放的是一个整型变量的指针(一级指针,或许就是上面那个a的值)。

30、变量的指针

以下代码的输出是 :

void swap( int *pa, int *pb ) 
{
    int pt;
    pt = *pa, *pa = *pb, *pb = *pa;
}
int main(void)
{    
    int x=1, y=2;
    swap(&x, &y);
    printf("%d%d", x, y);
}

答案:22

分析:看清楚swap函数,不是交换两个变量的地址,而是把pb的地址又赋给pa,即pa,pb均指向pb的地址。其实没必要这么麻烦,直接把pb的地址给pa就行。

 

  • 77
    点赞
  • 486
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吉大秦少游

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值