指针讲解(超难题目,注意你的cpu,不要超载了)

文章详细比较了C语言中的sizeof操作符与strlen函数的区别,解释了sizeof用于计算内存占用,strlen只关注终止符,同时深入剖析了数组名、数组指针和内存布局的概念。

我们先来二个小提示

sizeof这个操作符,他只在乎占用内存的空间,不在乎里面放了上面内容。

而strlen是c语言中的一个库函数,他不在乎占用内存的空间,只在乎\0,他是遇到\0就停下来。

再送你们二个小提示。

sizeof(数组名)表示整个数组,计算的是整个数组的大小

&数组名,表示整个数组,取出的是整个数组的地址,加1表示跳过整个数组的地址。

第一阶级

答案在全部题目的后面

int main()
{
    int a[3][4] = { 0 };
    printf("%zd\n", sizeof(a));
    printf("%zd\n", sizeof(a[0][0]));
    printf("%zd\n", sizeof(a[0]));
    printf("%zd\n", sizeof(a[0] + 1));
    printf("%zd\n", sizeof(*(a[0] + 1)));
    printf("%zd\n", sizeof(a+1));
    printf("%zd\n", sizeof(*(a + 1)));
    printf("%zd\n", sizeof(&a[0] + 1));
    printf("%zd\n", sizeof(*( & a[0] + 1)));
    printf("%zd\n", sizeof(*a));
    printf("%zd\n", sizeof(a[3]));

    return 0;
}

我不要图片就是为了你们更好复制在自己的电脑上面运行。

    printf("%zd\n", sizeof(a));

这个上面写了sizeof(数组名)表示整个数组的地址,所以3*4为12个元素,int型的12*4=48,是不是很简单,不急慢慢来,后面有你们啊……的。
    printf("%zd\n", sizeof(a[0][0]));

这个不就是第一个元素吗,没难度,就是4。恭喜你哦,又对了一题。
    printf("%zd\n", sizeof(a[0]));

这个上一章讲过了,a[0]这个是数组指针,指向的是第一行的地址,是4个元素,就是4*4个字节。厉害确实对了,但是理解错了,上面说,sizeof(数组名)是整个数组的地址,但是他有【0】啊,那他就不是第一行全部的元素了,是一个地址,噢,那就是4\8个字节,那又错了,我们二维数组在内存中,是连续储存的,并且每一行,都会看为一维数组,而第一行的数组名我们就把他叫为a[0],所以这个计算的是一维数组(二维数组的第一行)的全部大小,计算4个元素,计算4*4个字节,怎么样,喜欢吗。这不和悬疑片一样一直反转吗。
    printf("%zd\n", sizeof(a[0] + 1));

a[0]+1,这个就是a[0]加1嘛,a[0]就是第一行的全部大小,16个字节,那a[0]+1,就是

第一行的第二个元素,那就是4个字节

对了答案都是这个,

哈哈哈……………………,又错了。我们想上面我们为什么说

a[0]是计算的是整个一维数组,而不是第一行的地址啊,因为他是数组名,而a[0]+1,这个是数组名吗,不是啊。那他就是一个地址,4\8个字节。我这个特意调86位就为了给你们看这个,现在我改64就知道了

你们说多么相信我说的,结果我先说错的。哈哈哈…………兄弟和我心连心,我和兄弟玩脑筋。
    printf("%zd\n", sizeof(*(a[0] + 1)));

这个是什么,a【0】+1是第一行的第二个元素,再解引用,不就是一个int的元素吗,就是4个字节
    printf("%zd\n", sizeof(a+1));

这个是a+1,不是一个单独的a,那就是地址,地址的字节都知道,后面就不打了。
    printf("%zd\n", sizeof(*(a + 1)));

*(a+1)这个是什么东西,大家都知道吧,上章说了,这个是意思就是a【1】这个是不是数组名啊,那就是第二行全部的大小,为16个字节
    printf("%zd\n", sizeof(&a[0] + 1));

既然看到了&符号,那就是一个地址,知道了吧
    printf("%zd\n", sizeof(*( & a[0] + 1)));

这个先是&a[0]那就是第一行的地址,再+1,那就是第二行的地址,在解引用,就是什么。大家想一下,第二行的地址,是一个数组指针,他解引用会是什么,是一个元素,还是一个数组。那肯定是一个数组,所以他解引用出来的是4*4个字节
    printf("%zd\n", sizeof(*a));

大家看到sizeof(*a),会想到什么,可以想到sizeof(a),如果你想到了,那就寄了,他们很像但是就是没关系。所以我们还是,按之前的套路来,先&a,这个就是首元素地址啊,难道忘了吗。首元素地址解引用是什么自己想,上一个讲的就是。你理解了吗?
    printf("%zd\n", sizeof(a[3]));

这个东西你看过去是不是感觉没什么问题,但是int arr【3】【4】所以,把arr看为一维数组的话,arr[1],arr[2],arr[0]哪里有3啊,是不是就越界了,越界了。就不可以访问了。但是他这里不会报错,为什么呢,你想我用了吗,欸,你不是写了sizeof吗,难道不是用了吗。我们对这个地址访问是会报错,但是是访问,我们没有访问啊,我们就单纯的计算他的大小。还是可以的。

最后是答案

大家可以自己尝试一下,strlen,我感觉strlen的在编辑器上面有些打不出来,很多都会报错,我就不搞了。这个数组都是二维数组,我感觉二维数组如果都会的话,一维数组对你来说就是小意思了。当然我知道这样跨度有点大,但是我默认你们把前面的都吸收了再来看的,那就是可以接收的。

第二阶段

int main()
{
    int a[5][5];
    int(*p)[4];
    p = a;
    printf("%p\n%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
    return 0;
}

对这个阶段很简单,就这一个题。但是这个题,呵呵。

我们前面讲过二维数组在内存中的储存的连续的,因此int a [5][5]在内存中的表示为

这些格子就够了。

而我们把a的地址赋给p,那p指向的地址就是a的地址而p是int (*)[4]的指针

因此,&p[4][2]怎么变,知道吗。这个东西真的很重要,我这么多关于指针文章基本上每张都有。这个也是最后一章了。最后走一遍。

首先是p[4][2]我们分开看,先是p[4]这个我们前面说是怎么变的,就是变为*(p+4)我们在看,因为p是一个int *【4】的指针那么,一个就是访问4个int类型,4*4就是16个整形。因此,我们向后数16个整形

因此,从17到20就是p[4](这个是数组名)中的元素,p[4][2]就是在p[4]的基础上在加一个2,从17开始向后数二个就是19,所以19就是p[4][2]

而a[4][2]只要学了数组的都知道,因为这个就是常规的,我直接说就是23。而二个地址相减计算的就是这个地址之间的地址,就是23-19=4,但是计算机的地址是从低地址到高地址,因此为-4,因此,%d打印的就是-4,而%p是以地址的形式打印,而-4在电脑中的储存为

但是,以地址的形式打印,电脑不会把补码变为原码,就以补码为地址打印。

怎么样,cpu还好吧,什么干烧了。还有呢,你不会坚持不下去了吧。

放心,我就再来一个,就一个了。一定要坚持噢,一个也就和上面一样多,还是不多的好吧。

第三阶段

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

首先,char*c[],这个你们认为是什么,我直接说,这个是一个数组,每个元素都是char*(但是这个不是指向一个字符,而是一个字符串)的元素,所以这是指针数组,而cp是什么,这是一个二级指针数组,是一个数组,但是每一个元素都是一个二级指针,而cpp是一个三级指针,而三级指针存放的就是二级指针的地址。因此,图画出来就是

我建议大家如果真的想把这个消耗的话,自己在电脑的画板上画一下。现在我们开始讲题。

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

先是这个,因为是前置加加,所以先加加再使用,所以cpp向下走一个单位

因此,我们可以看到cpp指向了cp + 1,再解引用,看手写的表,就可以知道,这个指向的是POINT。

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

这个我们就要知道一下,运算符的优先级了,其实这个只要学了都知道,+3肯定是最后的,其他的从右到左,先++,

就指向了cp+2 ,在解引用,就到了c + 1(手写的)c+1 --,就变为了c再解引用,就到了ENTER

这个字符串,因为E是开头,在+3就到了E(第二个),因为是字符串,所以打印ER。

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

首先,cpp指向cp+2,所以cpp[-2]就是指向cp,解引用就到了c+3再解引用就是FIRST,+3就是ST

留一个给你们自己算

答案为

怎么样,喜欢吗。是不是学下来,什么都毁了。但是如果这个你都可以理解了的话,那么面试题你都可以了。因为,这个就是最难的面试题,你放心你面试的时候不会看到这么难的题。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值