指针习题练习

知识点复习

做题之前复习一个知识点——数组名的理解

数组名代表该数组首元素的地址,但是有两个例外:

1> &数组名,数组名代表整个数组的地址;

2> sizeof(数组名),数组名代表整个数组地地址;

开始练习吧!

题目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表示数组首元素的地址,a+1表示跳过一个整形的大小,*(a+1)表示指向这个地址的值,也就是2

&a 表示一个数组的地址,&a+1表示跳过一个数组的大小,然后(&a+1)强制转化成int*类型,让

ptr接收,那么ptr-1表示向后跳过一个整形的大小,*(ptr-1)表示指向这个地址的值,也就是5.

图解:

代码运行结果:

题目2

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
    int Num;
    char* pcName;
    short sDate;
    char cha[2];
    short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{
    printf("%p\n", p + 0x1);
    printf("%p\n", (unsigned long)p + 0x1);
    printf("%p\n", (unsigned int*)p + 0x1);
    return 0;
}

分析:

我们知道结构体大小是20个字节(题上说的),定义一个结构体指针 pp里面放的是0x100000

因为p是结构体指针,并且结构体大小是20个字节,所以p+0x1表示跳过一个结构体的大小,也就是跳过20个字节,然后%p打印地址;

(unsigned long)p表示p是一个无符号长整形,p+1就是简单的+1,但这里用的%p打印,会出现警告,但这不影响,我们主要是理解指针加减的运算,先不用管它;

(unsigned int*)p表示将一个结构体指针转化成无符号整形指针,p+0x1表示跳过一个无符号整形的大小,也就是4个字节,然后%p打印地址;

图解:

代码运行结果:

 

题目3

# 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 ,注意给数组赋值是用的逗号表达式,(逗号表达式取最后一个逗号后面的值),

所以数组里面的值是 1,3,5,0,0,0

指向 a[0] ,也就是二维数组的首元素,p[0]表示*(p+0),这里的 表示一维数组的数组名,也就是一维数组首元素的地址,也就是1的地址,*(p+0)其实就是1。

图解:

代码运行结果:

题目4

// 假设环境是 x86 环境,程序输出的结果是啥?
# 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 ;
}

 

分析:

int(*p)[4] 是一个数组指针,指向的数组有4int类型的元素,将a赋值给p,但是类型有一些不一样,会出现警告,但我们就是要赋值给p,别问,问就是这么强横(还不是为了刁难你,该死的出题人),a表示二维数组的首元素的地址,也就是a[0], 

p[4]表示*(p+4),这里的p表示指向一个有4个整形的数组的地址,p[4][2]表示*(p[4]+2),这里的p[4]

表示一个有4个整形的数组的数组名,也就是数组的首地址,p[4]+2表示跳过2个整形的大小,

   &p[4][2] - &a[4][2]这个我们看图就很好理解了,指针相减的绝对值表示相差元素的个数

图解: 

 

代码运行结果:

 

题目5 

#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;
}

分析: 

 &aa指的是整个二维数组的地址,&aa+1指的是跳过一个二维数组的大小,

&aa+1转化成int*类型,让ptr1接收,ptr1-1指的是向后跳过一个整型指针的大小*(ptr1-1)就是10

aa表示二维数组的首元素的地址也就是aa[0]aa+1指的是跳过一个一维数组的大小,然后解引用相当于aa[1]

aa[1]转化成(int*)类型,让ptr2接收,prt2-1指的是向后跳过一个整形的大小,最后解引用*(ptr2-1),就是5

图解:

代码运行结果:  

题目6

#include <stdio.h>
int main()
{
    char* a[] = { "work","at","alibaba" };
    char** pa = a;
    pa++;
    printf("%s\n", *pa);
    return 0;
}

分析: 

 a是一个char类型的指针数组,放有三段字符串,

char*  *pa=a;

  pa 是一个指向char* 类型的指针,a相当于数组的首元素的地址

pa++;相当于跳过一个字符串,//类似于二维数组

此时pa指向第二个字符串的首地址,对 pa  解引用,

相当于得到的是 ’a‘ ,用 %s 打印字符串,遇到 \0 停止

图解:

代码运行结果:

 题目7(较难)

#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;
}

分析1:

printf("%s\n", **++cpp);

++cpp,相当于 cpp  跳过一个 char** ,指向下标为1,也就是c+2的地址

*(c+2) 解引用后表示 c+2指向的下标为2的char*类型的地址,

 **(c+2) 解引用相当于 P , %s 打印字符串

结果就是:POINT

看图很容易理解,一次指针加法运算,两次解引用

图解1:

分析2:

printf("%s\n", *-- * ++cpp   + 3);

在上一条语句运行的前提下,++cpp再跳过一个char**,指向下标为2,也就是c+1的地址,

*(++cpp)解引用后表示c+1,然后 --(c+1) , c+1 指向下标为1char* 类型的地址,--(c+1)相当于

指向下标为0char* 类型的地址,*(--(c+1)) 解引用后相当于E,最后在加3,跳过3个整形大小,用%s打印,

结果是:ER

比较绕,可以结合图解多看几遍,更容易理解。

图解2:

分析3: 

 printf("%s\n", *cpp[-2] + 3);

在前两条语句运行的前提下,cpp此时指向下标为2的地址

cpp[-2] 等价于*(cpp-2),解引用后相当于 c+3 c+3 指向下标为3的char*类型的地址,

也就是F的地址,最后加3,跳过3个整形大小,%s打印,

结果是:ST

图解3:

分析4:

 printf("%s\n", cpp[-1][-1] + 1);

在前三条语句运行的前提下,cpp此时依然指向下标为2的地址,因为在上一条printf语句中

cpp没有做运算

cpp[-1]等价于*(cpp-1),解引用后相当于 c+2,  c+2 指向下标为2char* 类型的地址,

c+2[-1] 等价于*((c+2)-1), 解引用相当于指向下标为1的元素,也就是N,

最后加1,跳过1个整形大小,%s打印,

结果是:EW

图解4:

代码运行结果:

     制作不易,希望给你带来帮助!

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值