C语言指针运算题
1. 题目1
代码如下,推测程序的结果:
#include <stdio.h>
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int *ptr = (int *)(&a + 1);printf( "%d,%d", *(a + 1), *(ptr - 1));return 0;
}
我们逐层解析:
首先代码创建了一个整型数组a,并且进行了初始化。
接着,创建一个整型指针变量ptr,ptr指向地址是(&a+1)。操作符&加上数组名a,得到的是整个数组的地址,+1后会跳过整个数组,指向的是数组后的地址,不过(&a+1)的指针类型为int(*)[5],因此赋值给指针ptr时,需要进行强制类型转化。
最后,打印两个整型变量。一个为*(a+1),另一个为*(ptr-1)。
*(a+1),数组名a与整数进行加减运算,那么a代表的是数组首元素的地址,+1后跳过一个元素,即指向数组中第二个元素的地址,解引用操作后得到该元素;ptr指向的是数组后的地址,因为ptr是整型指针变量,-1后会跳过一个整型变量的大小的空间,此时指向数组中最后一个元素的地址,解引用操作得到该元素。
因此,打印结果应该为:2,5
2,5
2. 题目2
代码如下,推测程序输出结果:
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int *p;p = a[0];printf( "%d", p[0]);return 0;
}
逐层解析:
首先,创建一个二维数组a,一共三行两列,并且进行初始化。
创建整型指针变量p,并将数组首元素地址赋值给p。
打印数组首元素。
那么关键就在于判断数组中的元素。有意思的时,这串代码在初始化数据时虽然形式上与分行初始化十分相似,但是分行初始化使用的是大括号{ },而不是圆括号( ),所以说,这里初始化数据使用的是逗号表达式,返回值位括号中最右侧的值,也就是说数组中元素实际为 1,3,5,0,0,0
那么,输出结果应该是:1
1
我们可以将数组元素全部打印出来,判断我们的分析是否正确:
#include <stdio.h>
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int i,j;for(i = 0;i < 3;i++){for(j = 0;j < 2;j++){printf("%d ",a[i][j]);}printf("\n");}return 0;
}
1 3
5 0
0 0
3. 题目3
代码如下,推测程序输出结果:
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
逐层分析:
首先创建一个二维整型数组a,一共有五行五列。
然后创建一个指针变量p,类型为int(*)[4],将数组a的地址赋值给指针p。
最后分别以地址和整型打印出&p[4][2] - &a[4][2]的结果。
我们发现,a作为二维数组名,单独使用时属于指针,指向的是整个第一行a[0],类型为int(*)[5]。我们发现p与a的类型不同,因此在将a的地址赋值给p后,a+1与p+1所跳过的内存大小是不同的。a+1跳过 5 * 4 = 20个字节,而p+1则跳过 4 * 4 = 16个字节。那么a[0]一共有5个元素,p[0]一共有4个元素。
我们知道,指针-指针得到的结果是两个地址之间的元素个数。
那么&p[4][2] - &a[4][2]运算就是 (4 * 4 + 3) - (4 * 5 + 3) = -4
所以以整型形式打印出来结果就是-4,而在以地址形式打印出来时,编译器就是会将其作为64位的无符号整数来打印(64位系统下),具体形式如下:
-4
//原码
10000000 00000000 00000000 00000000 00000000 00000000 00000000 00000100
//反码
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111011
//补码
11111111 11111111 11111111 11111111 11111111 11111111 11111111 11111100
//转化为16进制的地址形式
FF FF FF FF FF FF FF FC
所以打印结果就应该是:FFFFFFFFFFFFFFFC,-4
FFFFFFFFFFFFFFFC,-4
4. 题目4
代码如下,推测程序输出结果:
#include <stdio.h>
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);int *ptr2 = (int *)(*(aa + 1));printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}
逐层分析:
这题与题目1的思维类似,区别在于这里创建的是二维数组
创建二维整型数组aa并初始化,创建两个整型指针变量ptr1和ptr2,分别赋值(&aa + 1)和(*(aa + 1))。
&aa+1,aa为二维数组名,&aa得到整个数组的地址,+1后跳过整个数组,指向数组后的地址。类型为int(*)[2][5],赋值给ptr1时需要进行强制类型转换。
*(aa+1),aa为二维数组名,无操作符sizeof与&时,代表的是二维数组首行的地址,类型为int(*)[5],+1后跳过整行,指向第二行。解引用操作后得到整个第二行aa[1],类型为int *,这时赋值给ptr2时并不需要进行强制类型转换,即使使用了,也不会出现语法错误。
分析完这些后,我们开始分析打印结果。
ptr1指向的是数组后的位置,类型为int *,-1后向前跳过一个整型元素大小的空间,也就是指向二维数组最后一个元素的地址,解引用操作后得到该元素,也就是10.
ptr2指向的是第二行首元素的地址,-1后向前跳过一个元素,指向第一行最后一个元素的地址,解引用操作后得到该元素,也就是5。
所以,打印结果为:10,5
10,5
5. 题目5
代码如下,推测程序输出结果:
#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}
逐层分析:
首先,创建一个字符指针数组,并进行初始化,存储三个字符串首字符的地址。
然后,创建一个二级字符指针pa,并将数组a首元素的地址赋值给pa。
接着让pa自增,最后打印该字符串。
pa指向的是数组a首元素的地址,自增操作后,向后跳过一个元素,指向数组中第二个元素,即第二个字符串首字符的地址的地址。解引用操作后,得到该字符串的首字符的地址。最后打印出字符串at。
at
6. 题目6
代码如下,推测程序输出结果:
#include <stdio.h>
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}
这题很复杂,一定要保证思路清晰:
首先,创建一级字符指针数组c,存储4个字符串首字符地址。
接着,创建二级字符指针数组cp,并存储4个一级字符指针:c+3,c+2,c+1,c
然后创建三级字符指针cpp,并将数组cp首元素地址赋值给cp
最后打印4行结果
我们逐个分析:
第一条:
**++cpp,cpp指向数组cp[0],自增操作后,指向cp[1],第一次解引用得到cp[1],即地址c+3。第二次解引用,得到c+3处的元素,即字符串"POINT"首字符地址P的地址,所以打印结果为"POINT"
第二条:
*--*++cpp+3,cpp此时指向cp[1],根据操作符优先级,先进行自增操作,此时指向cp[2],第一次解引用操作,得到cp[2],即地址c+1;接着,进行自减操作,此时,cp[2]指向c,第二次解引用操作得到c处的元素,即字符串"ENTER"首字符E的地址;+3后,向后跳过三个字符,所以打印结果为"ER"
第三条:
*cpp[-2]+3,cpp此时指向cp[2],根据操作符优先级,先进行cpp[-2]操作,可以转化为*(cpp-2),cpp-2则指向cp[0],第一次解引用得到cp[0]元素,即c+3;第二次解引用操作得到c+3处的元素,即字符串"FIRST"首字符地址;+3后向后跳过三个字符,所以打印结果未"ST"
第四条:
cpp[-1][-1]+1,此时cpp指向cp[2],根据操作符优先级,先进行cpp[-1][-1]操作,可以转化为
*(*(cpp-1)-1),从内向外,cpp-1指向cp[1],第一次解引用后得到cp[1],即地址c+2;c+2 - 1得到c+1,第二次解引用操作得到c+1处元素,即字符串"NEW"首字符"N"的地址,+1后向后跳过一个字符,所以打印结果为"EW"
POINT
ER
ST
EW