news 2026/6/9 11:13:50

关于数组和指针的一些问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
关于数组和指针的一些问题
#include <stdio.h> #include <string.h> int main() { //指针和数组笔试题解析 int a[] = { 1,2,3,4 }; printf("%d\n", sizeof(a));//16 a==&a[0] //sizeof(数组名),计算的是整个数组的大小单位是字节 printf("%d\n", sizeof(a+0));//4/8 a+0==&a[0]+0 //这里a表示数组首元素地址,a并没有单独放在sizeof内部,也没有取地址, //所以a就是首元素地址,a+0还是首元素地址 printf("%d\n", sizeof(*a));//4 *a==*&a[0] //*a中的a是数组首元素的地址,*a就是对首元素的地址解引用,找到的就是首元素 //首元素的大小就是4个字节 printf("%d\n", sizeof(a+1));//4 a+1==&a[0]+1 //这里的a是数组的首元素地址,a+1是第二个元素的地址 printf("%d\n", sizeof(a[1]));//4 //计算的是第二个元素的大小 printf("%d\n", sizeof(&a));//4/8 //&a取出的是数组的地址,数组的地址,也就是个地址 printf("%d\n", sizeof(*&a));//16 //&a---->int(*)[4] //&a拿到的是数组名的地址,类型是int(*)[4],是一种数组指针 //*&a----->a //也就是可以理解成:&和*相互抵消了,所以只有a了,就代表整个数组的大小了 printf("%d\n", sizeof(&a+1));//4/8 //&a取出的是数组的地址 //&a---->int(*)[4] //&a+1是从数组a的地址向后跳过了一个(4个整形元素的)数组的大小 //&a+1 还是地址,是地址就是4/8字节 printf("%d\n", sizeof(&a[0]));//4/8 //&a[0]就是第一个元素的地址 //计算的是地址的大小 printf("%d\n", sizeof(&a[0]+1)); //&a[0]就是第二个元素的地址 //大小是4/8个字节 //&a[0]+1---->&a[1] // char ass[] = { 'a','b','c','d','e','f' }; printf("%d\n", sizeof(ass));//6 //sizeof(数组名) printf("%d\n", sizeof(ass+0));//4/8 //ass+0 是数组首元素地址 printf("%d\n", sizeof(*ass));//1 //*ass就是数组的首元素,大小是1字节 //*ass --> ass[0] //*(ass+0) --> ass[0] printf("%d\n", sizeof(ass[1]));//1 printf("%d\n", sizeof(&ass));//4/8 //&ass是数组的地址,地址就是4/8个字节 printf("%d\n", sizeof(&ass+1));///4/8 //&ass+1是数组后的地址,跳过了整个数组 printf("%d\n", sizeof(&ass[0]+1));//4/8,&ass[0]会发生整型提升 //&ass[0]+1是第二个元素的地址 printf("%d", strlen(ass));//随机值 ///我们的数组中结尾并没有'\0',所以无法具体测量长度 printf("%d", strlen(ass+0));//随机值,与上述相同的原因 //printf("%d", strlen(*ass));//--> strlen('a')--strlen(97);//野指针问题 //printf("%d", strlen(ass[1]));//-->strlen('b')-->strlen(98) //printf("%d", strlen(&ass));//&ass取出数组地址,依旧随机值 //printf("%d", strlen(&ass+1));//随机值-6 //printf("%d", strlen(&ass[0]+1));//随机值 char arr1[] = "abcdef"; printf("%d\n", sizeof(arr1));//7 //a b c d e f \0 printf("%d\n", sizeof(arr1+0));//4/8 printf("%d\n", sizeof(*arr1));//1 printf("%d\n", sizeof(arr1[1]));//1 printf("%d\n", sizeof(&arr1));//4/8 printf("%d\n", sizeof(&arr1+1));//4/8 printf("%d\n", sizeof(&arr1[0]+1));//4/8 //strlen 是求字符串长度的,关注的是字符串中的\0,计算的是\0之前出现的字符的个数 //strlen是库函数,只针对字符串 //sizeof只关注占用内存空间的大小,不在乎内存中放的是什么 //sizeof是操作符 printf("%d\n", strlen(arr1));//6 printf("%d\n", strlen(arr1 + 0));//6 //printf("%d\n", strlen(*arr1));//err //printf("%d\n", strlen(arr1[1]));//err //printf("%d\n", strlen(&arr1));//6 //printf("%d\n", strlen(&arr1 + 1));//随机值 //printf("%d\n", strlen(&arr1[0] + 1));//5 const char* p = "abcdef"; printf("%d\n", sizeof(p));//4/8 printf("%d\n", sizeof(p+1));//4/8 printf("%d\n", sizeof(*p));//1 printf("%d\n", sizeof(p[0]));//1 printf("%d\n", sizeof(&p));//4/8 printf("%d\n", sizeof(&p+1));//4/8 printf("%d\n", sizeof(&p[0]+1));//4/8 printf("%d\n", strlen(p));//6 printf("%d\n", strlen(p+1));//5 //printf("%d\n", strlen(*p));//err //printf("%d\n", strlen(p[0]));//err //printf("%d\n", strlen(&p));//随机值 //printf("%d\n", strlen(&p+1));//随机值-5 printf("%d\n", strlen(&p[0]+1));//5 //二维数组 int a[3][4] = { 0 }; printf("%d\n", sizeof(a));//48 printf("%d\n", sizeof(a[0][0]));//4 printf("%d\n", sizeof(a[0]));//16 //a[0]是第一行这个一维数组的数组名,单独放在sizeof颞部,a[0]表示第一个整个这个一维数组 //sizeof(a[0])计算的就是第一行的大小 printf("%d\n", sizeof(a[0]+1));//4 --a[0][0]+1 //a[0]并没有单独放在sizeof内部,也没取地址,a[0]就是首元素的地址 //就是第一行这个一维数组的第一个元素的地址,a[0]+1就是第一行第二个元素的地址 printf("%d\n", sizeof(*(a[0]+1));//4 //a[0] + 1就是第一行第二个元素的地址 //*(a[0] + 1)就是第一行第二个元素 printf("%d\n", sizeof(a+1));//4/8 //a虽然是二维数组的地址,但是并没有单独放在sizeof内部,也没取地址 //a表示首元素地址,二维数组的首元素是他的第一行,a就是第一行地址 //a+1就是跳过第一行,表示第二行的地址 printf("%d\n", sizeof(*(a+1));//16 //*(a+1)是对第二行地址的解引用拿到的是第二行的大小 //*(a+1)-->a[1] printf("%d\n", sizeof(&a[0]+1));//4/8 //&a[0]是第一行的数组名,拿出的是第一行的地址 //&a[0]+1得到的是第二行的地址 printf("%d\n", sizeof(*(a[0]+1));//16 printf("%d\n", sizeof(*a));//16 //a表示首元素的地址,就是第一行的地址 //*a就是第一行地址的解引用,拿到的就是第一行 printf("%d\n", sizeof(a[3]));//16 printf("%d\n", sizeof(a[0]));//16 一个道理 //数组名的意义 /* 1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小 2.&数组名,这里的数组名表示整个数组,取出的是整个数组的地址 3.除此之外所有的数组名都表示首元素的地址 */ return 0; }

#include <stdio.h> void test1() { int a[5] = { 1,2,3,4,5 }; int* ptr = (int*)(&a + 1);//&a是数组的地址-->int(*)[5] //&a+1跳过了整个数组, printf("%d %d\n", *(a + 1), *(ptr - 1));//2 5 } struct Test {//这里告知结构体的大小是20个字节 int Num; char* pcName; short sDate; char cha[2]; short sBa[4]; }*p = (struct Test*)0x100000; //假设p的值为0x100000。test2中表达式的值分别是多少, //已知,结构体Tset类型的变量大小是20个字节 //x86环境 void test2() { printf("%p\n", p + 0x1);//16进制表示20-->14 //0x100000+20-->0x100014 printf("%p\n", (unsigned long)p + 0x1); //(unsigned long)p-->1048576+0x1-->1048576+1->1048577-->0x100001 printf("%p\n", (unsigned int*)p + 0x1); //0x100000+4-->0x100004 } void test3() { int a[4] = { 1,2,3,4 }; int* ptr1 = (int*)(&a + 1); int* ptr2 = (int*)((int)a + 1);//%x,打印16进制 //假设a=0x00012ff40 //a+1-->0x0012ff44 //(int)a+1-->0x12ff41,处于1-2之间 printf("%x,%x", ptr1[-1], *ptr2);//4 2000000 //低-----------------------------------高 //10 (00 00 00 02) 00 00 00 03 00 00 00 04 00 00 00 //ptr2-->00 00 00 02 //小端 //ptr1[-1]-->*(ptr1+(-1))-->*(ptr1-1) } void test4() { int a[3][2] = { (0,1),(2,3),(4,5) };//实际-->{ 1, 3, 5 ,0 , 0, 0} int* p; p = a[0]; printf("%d", p[0]);//1 p[0]-->*(p+0) } //void test5() {//x86 // int a[5][5]; // int (*p)[4]; // p = a; // //-4 // //补码:11111111111111111111111111111100 // //16进制:FF FF FF FC // printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);// -4 // /* // p[4][2]-->*((p+4)+2) |&p[4][2] // [][][][][][][][][][][][][][][][][][][][][][][][][] // 0 1 2 3 4 |&a[4][2] // |p |p+1 |p+2 |p+3 |p+4 // */ // } void test6() { 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\n", *(ptr1 - 1), *(ptr2 - 1));//10 5 } void test7() { const char* a[] = { "work","at","alibaba" }; const char** pa = a; pa++; printf("%s\n", *pa);//at } void test8() { const char* c[] = { "ENTER","NEW","POINT","FIRST" }; const char** cp[] = { c + 3,c + 2,c + 1,c }; const char*** cpp = cp; printf("%s\n", **++cpp);//POINT printf("%s\n", *-- * ++cpp + 3);//ER printf("%s\n", *cpp[-2] + 3);//ST printf("%s\n", cpp[-1][-1] + 1);//EW } int main() { /*test1(); test2(); test3(); test4(); test5(); test6(); test7();*/ test8(); return 0; }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/9 21:25:39

3步轻松解锁原神帧率:告别60帧限制的完整指南

还在为《原神》60帧限制而烦恼吗&#xff1f;这款专为原神玩家打造的帧率解锁工具&#xff0c;能让你彻底摆脱帧率束缚&#xff0c;享受丝滑流畅的游戏体验&#xff01;无论你是高刷显示器用户还是追求极致画面的玩家&#xff0c;这份指南都将帮助你轻松完成设置。 【免费下载链…

作者头像 李华
网站建设 2026/6/9 16:40:37

用户投诉处理指南:LobeChat建议妥善回应

用户投诉处理指南&#xff1a;LobeChat建议妥善回应 在客户服务领域&#xff0c;每一次用户投诉都是一次信任的考验。尤其是在AI驱动的时代&#xff0c;用户不再满足于“机器人式”的模板回复——他们期待的是理解、共情与高效解决。如何让AI客服既能快速响应&#xff0c;又能像…

作者头像 李华
网站建设 2026/6/9 1:32:21

6、深入理解 Linux 文件与目录权限管理

深入理解 Linux 文件与目录权限管理 1. 权限设置概述 在 Linux 系统中,我们可以通过三种方式设置权限来限制对文件或目录的访问: - 仅限制自己访问。 - 允许预指定组的用户访问。 - 允许系统上的任何人访问。 同时,我们还能控制对特定文件或目录的访问方式。 2. 文件…

作者头像 李华
网站建设 2026/6/8 14:16:04

《Ionic 侧栏菜单》

《Ionic 侧栏菜单》 引言 随着移动应用开发技术的不断进步,用户体验成为了开发者关注的焦点。在众多前端框架中,Ionic凭借其丰富的组件库和便捷的开发流程,成为了移动应用开发的热门选择。在Ionic中,侧栏菜单(Side Menu)是一个非常实用的组件,它可以帮助用户在应用中快…

作者头像 李华
网站建设 2026/6/9 16:32:36

人工智能在健康医疗软件中的应用

人工智能在健康医疗软件中的应用关键词&#xff1a;人工智能、健康医疗软件、医疗诊断、疾病预测、医疗影像分析摘要&#xff1a;本文深入探讨了人工智能在健康医疗软件中的应用。首先介绍了相关背景&#xff0c;包括目的范围、预期读者等内容。接着阐述了人工智能与健康医疗软…

作者头像 李华
网站建设 2026/6/8 22:28:06

5分钟快速配置:告别消息撤回困扰的完整解决方案

5分钟快速配置&#xff1a;告别消息撤回困扰的完整解决方案 【免费下载链接】Anti-recall Android 免root 防撤回神器 ! 项目地址: https://gitcode.com/gh_mirrors/an/Anti-recall 你是否遇到过这样的情况&#xff1a;工作群里的重要通知刚发布就被撤回&#xff0c;朋友…

作者头像 李华