写在前面
本篇总结的是和指针相关的有难度的选择题,并对这些题进行解析和分析
形参和实参
下面程序的运行结果是什么?
#include <stdio.h> void func(char* p) { p = p + 1; } int main() { char s[] = { '1','2','3','4' }; func(s); printf("%c", *s); return 0; }
首先传参是数组名,这里的数组名代表的是首元素的地址,但传过去的并不是数组名的地址,func函数内部对p的改变不改变外部数组s,因此输出的应该为1
二维数组传参
已知数组D的定义是int D[4][8]
,现在要把这个数组作为实参传递给一个函数处理,下列可以作为形参变量的是
A. int D[4][] B. int *s[8] C. int(*s)[8] D. int D[][8]
这里的数组D是一个二维数组,那么就首先要清楚二维数组传参传的是什么,二维数组传参传递的是二维数组中首元素的地址,也就是第一个一维数组的地址,也就是数组指针
数组指针是一个指向数组的指针
int *s[8] -> 这是指针数组,数组名是s,里面存着8个指针
int (*s)[8] -> 这是数组指针,指针名是s,指针指向一个大小为8的数组
因此这里ABCD中要选一个数组指针,因此选的是C
字符数组
下面程序的运行结果是什么?
#include <stdio.h> void fun(char** p) { int i; for (i = 0; i < 4; i++) { printf("%s", p[i]); } } int main() { char* s[6] = { "ABCD", "EFGH", "IJKL", "MNOP", "QRST", "UVWX" }; fun(s); printf("\n"); return 0; }
char
类型的数组内只能存储单个字符,这里改成了char*
类型的数组,意思就是存储的是这些字符串的地址,因为一个字符串会被编译器看成const char*
类型,因此存储到数组中相应的数组的类型就是char*
类型的数组
而fun函数传参,传的是数组,数组名代表的是首元素的地址,因此接收函数的形参类型就是char**
而函数中的p[i]
又可以看成是*(p+i)
,因此输出的就是ABCDEFGHIJKLMNOP
二维数组
数组a的定义为int a[3][4]
,下面哪个不能表示a[1][1]
A. *(&a[0][0]+5) B. *(*(a+1)+1) C. *(&a[1]+1) D. *(a[1]+1)
先看A选项,&a[0][0]
表示二维数组中元素的地址,该元素的地址+5表示向后加5个元素的地址,再对该地址进行解引用,得出的就是a[1][1]
再看B选项,*(a+1)
表示的就是a[1]
,而*(a[1]+1)
表示的就是a[1][1]
再看C选项,应该改为*(&a[1][0]+1)
,因为a[1]
就表示a[1][0]
的地址
D选项,由B选项可知这是正确的
函数指针数组
void (*s[5])(int)
是什么意思?
这里涉及到的是函数指针数组的概念,s首先和[]结合,证明这里的s是一个数组,数组中存储的内容类型是void (*)(int)
,那这又是什么?这就是函数指针,该指针指向的函数的参数是int,返回类型是void
参数匹配
- 下面参数调用匹配的是
void f(int** p); int a[4] = { 1,2,3,4 }; int b[3][4] = { {1,2,3,4},{5,6,7,8},{9,10,11,12} }; int* q[3] = { b[0],b[1],b[2] };
A.f(a) B.f(b) C.f(q) D.f(&a)
这里需要f函数的参数是int**
,意味着传参的参数要和这个匹配
A:如果传参的参数是a,这里的a代表的是首元素的地址,对应的参数应该是int*
B:如果传参的参数是b,由于b是二维数组,传参传的是二维数组中第一个数组的地址,传的是数组指针,对应的参数是int (*)[]
C:这个是符合的,传参首元素的地址,对应的是int**
D:&a表示的取出的是整个数组的地址,和A选项从数值上来看是一样的,区别是+1的问题
- 有定义语句:
char s[3][10],(*k)[3],*p
,下面赋值错误的是
p=s; p=k; p=s[0]; k=s;
因此这里就要看s,k,s[0],p分别代表什么类型了
首先看s:s是二维数组,因此这里s的类型是数组指针->char (*)[]
再看k:k就是数组指针,类型和s相同char (*)[]
再看s[0]:s[0]是二维数组中第一行数组,因此s[0]是一个一维数组,对应类型就是char*
最后是p:p类型是char*
,这个很明显
因此赋值等号两边类型得相同,因此第一个第三个第四个都不同
- 下面对fun函数调用正确的是:
char fun(char*); int main() { char* s = "one"; char a[5] = { 0 }; char (*f1)(char*) = fun; char ch; return 0; }
A: *f1(&a);
B: f1(*s);
C: f1(&ch);
D: ch = *f1(s);要改成(*f1)(s)才正确
首先看函数,定义了一个字符串s,第二个定义了一个字符数组,内的元素都是0,重点看f1:
f1是函数指针,f1指向的函数参数是char*,返回值是char,也就是说f1是函数fun的指针
那么分析选项:
首先要分清楚,(*f1)(&a)
和f1(&a)
和*f1(&a)
在函数指针调用中(*f1)(&a)
和f1(&a)
效果是一样的,但是*f1(&a)
会被认为是对返回值的解引用
A: *f1(&a);
:括号的优先级大于解引用,&a表示的是取出数组a的地址,类型是char*
符合函数指针调用参数,因此f1(&a)
会返回char类型的数据,但对它解引用这是错误的
B: f1(*s);
:*s参数不匹配
C: f1(&ch);
:没问题
D: ch = *f1(s);要改成(*f1)(s)才正确
:区分清上面的含义这个不难理解
多级指针
下面程序运行结果是?
#include<stdio.h> int main() { static char* s[] = { "black", "white", "pink", "violet" }; char** ptr[] = { s + 3, s + 2, s + 1, s }, *** p; p = ptr; ++p; printf("%s", **p + 1); return 0; }
首先定义了s数组,里面存的是字符串首元素的地址
下面的ptr是二级指针,存储的是s数组的,拿其中一个进行分析,ptr数组中存储的s+1,实际上对应的是s数组中下标为1的元素对应的地址,而又由于s数组中下标为1的元素是一个指针,因此这里ptr存储的是一个二级指针
后面又定义了p,ptr表示的是s+3的地址,s+3本身是二级指针,因此ptr就是三级指针
++p表示此时p由原来指向的s+3变成了s+2
在后面输出的部分,p现在指向的是s+2,因此*p
就是s+2
,再对它解引用*pp
也就是*(s+2)
也就是s[2]
,而s[2]
对应的是pink,因此这里指向的就是p,再+1指向的就是i,因此打印结果就是ink