制作好的网站必须申请,闸北区网站建设网,网站建设服务内容,网络小程序开发公司sizeof 和 strlen 首先我们来复习一下sizeof 和 strlen 的区别。 sizeof 是操作符#xff0c;只关注内存中存放的数据的大小#xff0c;并不会参与sizeof 括号内部的计算。注意它的单位是字节
#include stdio.hint main()
{int a 10;printf(%d\n, size…sizeof 和 strlen 首先我们来复习一下sizeof 和 strlen 的区别。 sizeof 是操作符只关注内存中存放的数据的大小并不会参与sizeof 括号内部的计算。注意它的单位是字节
#include stdio.hint main()
{int a 10;printf(%d\n, sizeof(a));printf(%d\n, sizeof a);printf(%d\n, sizeof(int));return 0;
}由于a 是 int 类型的数据需要的参数为指针地址并且 int 占四个字节的空间大小所以上面三行的 sizeof 计算出来都是 4 我们来看一下运行的结果吧
strlen 是 string.h 的库函数主要是计算字符串的长度当遇到 \0 的时候会停止计算长度。计算出来的是字符个数。
#include stdio.h
#include string.hint main()
{char arr1[3] { a, b, c };char arr2[] abc;printf(%d\n, strlen(arr1));printf(%d\n, strlen(arr2));return 0;
}由于 strlen 遇到 \0 才会停止计算所以计算 arr1 的长度时由于不知道什么时候遇到 \0 所以结果是一个不确定的数也就是随机数 而计算 arr2 的时候我们发现 arr2 存放的时一个字符串也就是说 arr2 实际存储的内容为 a b c \0 这四个字符由于 strlen 遇到 \0 就会停止计算也就是说明最后的结果为 3
我们来看一下运行的结果吧
数组名再深入理解 我们知道数组名一般来说是指数组的首元素的地址但是也有两个特殊情况一个是 sizeof (arr) 就是一个数组名单独放在sizeof 里面要注意了这里是取出的是整个数组计算的是整个数组的大小另外一个就是 arr ,它取出的是整个数组的地址那么数据类型是什么呢举个例子int arr [10] ,我们arr 取出整个数组的地址数据类型就是 int (*) [10]
#include stdio.h
int main()
{char arr1[3] { a, b, c };char arr2[] abc;printf(%d\n, sizeof(arr1));printf(%d\n, sizeof(arr2));return 0;
}由于sizeof(数组名)计算的是整个数组的大小也就是说我们只需要看数组占多大空间即可arr1[3]有三个元素每个元素的大小为 char (1个字节)总大小为 3 * 1 3 字节
arr2 没有明确说明大小那我们需要看一下其保存的字符串的大小也就是 a b c \0 一共有4个元素每个元素的是 char (1个字节总大小为 4 * 1 4 字节
我们来验证一下
题目剖析 这里我们通过一些题目来进一步地深入理解数组名与指针地关系。大家可以尝试自己分析一下下面代码的运行结果然后再看一下解析。
一维数组
#include stdio.hint main()
{int a[] { 1,2,3,4 };printf(%d\n, sizeof(a));printf(%d\n, sizeof(a 0));printf(%d\n, sizeof(*a));printf(%d\n, sizeof(a 1));printf(%d\n, sizeof(a[1]));printf(%d\n, sizeof(a));printf(%d\n, sizeof(*a));return 0;
}首先sizeof(a),数组名单独放在 sizeof 内部计算的是整个数组的大小也就是 4 * 4 16 个字节
sizeof(a0), a0说明数组名不是单独放在 sizeof 内部也就是 arr 指数组首元素的地址a0表示跳过0个元素还是数组首元素的地址地址就是 4/8 个字节64位机器地址占8个字节32位机器地址占4个字节
sizeof(*a) 数组名没有单独放在sizeof 内部就是说 a 代表的是数组首元素的地址*a数组首元素地址的解引用操作取出的是数组第一个元素sizeof 计算的就是数组第一个元素的大小也就是 4 个字节
sizeof(a1), 数组名没有单独放在sizeof 内部就是说 a 代表的是数组首元素的地址a1表示跳过一个元素表示第二个元素的地址既然是地址就是 4/8 个字节的大小
sizeof(a[1]), 这个a[1] 表示数组第二个元素也就是 4 个字节
sizeof(a), a 表示取出整个数组的地址数据类型是 int (*) [4] ,既然是地址也就是 4/8 个字节了。
我们来看一下运行结果这里以 64 位机器为例也就是地址大小为 8 个字节下面的运行示例也以 64 位机器演示就不做提醒了
字符数组
代码一
#include stdio.hint main()
{char arr[] { a,b,c,d,e,f };printf(%d\n, sizeof(arr));printf(%d\n, sizeof(arr 0));printf(%d\n, sizeof(*arr));printf(%d\n, sizeof(arr[1]));printf(%d\n, sizeof(arr));printf(%d\n, sizeof(arr 1));printf(%d\n, sizeof(arr[0] 1));return 0;
}sizeof(arr), sizeof 内部单独存放数组名计算的是整个数组的大小数组有 6 个元素分别为a b c d e f ;类型是 char 类型一个字节一共就是 6 * 1 6 字节
sizeof(arr0), arr 0 显而易见数组名不是单独存放再sizeof 内部arr 表示首元素的数组名arr 0表示跳过0个元素表示第一个元素的地址既然是地址也就是 4/8 个字节
sizeof(*arr), 数组名没有单独存放在 sizeof 内部arr则表示为数组首元素的地址*arr 解引用取出数组第一个元素数据类型为 char 即一个字节
sizeof(arr[1]),显而易见arr[1] 取出数组第二个元素大小为 1 个字节
sizeof(arr), arr表示取出整个数组的地址地址占 4/8 个字节
sizeof(arr1),arr 取出整个数组的地址数据类型是char (*) [6] , arr1跳过一个数组还是一个地址就是 4/8 个字节
sizeof(arr[0]1), arr[0] 取出的是数组首元素的地址1 表明跳过一个元素指向数组第二个元素还是一个地址 4/8 个字节
我们来看一下运行结果
代码二
#include stdio.h
#include string.hint main()
{char arr[] { a,b,c,d,e,f };printf(%d\n, strlen(arr));printf(%d\n, strlen(arr 0));printf(%d\n, strlen(*arr));printf(%d\n, strlen(arr[1]));printf(%d\n, strlen(arr));printf(%d\n, strlen(arr 1));printf(%d\n, strlen(arr[0] 1));return 0;
}strlen(arr),arr 表示首元素的地址遇到 \0 才停止计算是个随机数
strlen(arr0),arr 表示首元素地址 arr0表示跳过 0个元素指向第二个元素还是一个随机数
strlen(*arr), *arr 取出数组的首元素strlen 需要传入地址否则系统会报错无法运行硬要访问a的ascll码值是97访问的是地址编号为97这是属于操作系统的是不允许访问的
strlen(arr[1]), arr[1] 取出数组第二个元素系统报错硬要访问a的ascll码值是97访问的是地址编号为97这是属于操作系统的是不允许访问的
strlen(arr)arr 取出整个数组的地址不知道什么时候遇到 \0 ,是个随机数
strlen(arr1),arr 1 取出整个数组的地址并跳过一个数组是个随机数
strlen(arr[0]1), arr[0]1 取出首元素的地址跳过一个元素指向第二个元素是个随机数
代码三
#include stdio.hint main()
{char arr[] abcdef;printf(%d\n, sizeof(arr));printf(%d\n, sizeof(arr 0));printf(%d\n, sizeof(*arr));printf(%d\n, sizeof(arr[1]));printf(%d\n, sizeof(arr));printf(%d\n, sizeof(arr 1));printf(%d\n, sizeof(arr[0] 1));return 0;
}arr 存放着 a b c d e f \0 这 7 个元素
sizeof(arr),取出整个数组的大小 7 * 1 7 个字节
sizeof(arr0), arr 0 跳过 0 个元素指向数组第一个元素是个地址4/8 个字节
sizeof(*arr), *arr 表示数组首元素的解引用取出第一个元素1 个字节
sizeof(arr[1]), arr[1] 取出第二个元素大小为 1 个字节
sizeof(arr), arr 取出整个数组的地址数据类型是 char (*) [7] ,地址为 4/8 个字节
sizeof(arr1), 取出整个数组的地址并跳过一个数组还是一个地址4/8 个字节
sizeof(arr[0]1), 取出数组首元素的地址并跳过一个元素指向数组的第二个元素还是一个地址4/8 个字节
下面是代码运行结果
代码四
#include stdio.h
#include string.hint main()
{char arr[] abcdef;printf(%d\n, strlen(arr));printf(%d\n, strlen(arr 0));printf(%d\n, strlen(*arr));printf(%d\n, strlen(arr[1]));printf(%d\n, strlen(arr));printf(%d\n, strlen(arr 1));printf(%d\n, strlen(arr[0] 1));return 0;
}arr 存放着 a b c d e f \0 这 7 个元素
strlen(arr),传入数组首元素的地址遇到 \0 停下一共就是 6
strlen(arr0),传入数组首元素的地址并跳过 0 个元素还是指向数组首元素一共是 6
strlen(*arr), *arr 取出数组首元素不是一个地址系统报错硬要访问a的ascll码值是97访问的是地址编号为97这是属于操作系统的是不允许访问的
strlen(arr[1]),arr[1] 取出数组第二个元素不是一个地址系统报错硬要访问b的ascll码值是98访问的是地址编号为98这是属于操作系统的是不允许访问的
strlen(arr), arr 取出整个数组的地址还是以数组首元素的地址表示也就是 6
strlen(arr1), arr 1 取出整个数组的地址arr 的数据类型是 char (*) [7] ,并跳过一个数组也就是指向一个未知的空间无法知道什么时候遇到 \0 ,是个随机数
strlen(arr[0]1),arr[0]表示数组首元素的地址1 跳过一个元素也就是从第二个元素开始计算则为 5
代码五
#include stdio.hint main()
{char* p abcdef;printf(%d\n, sizeof(p));printf(%d\n, sizeof(p 1));printf(%d\n, sizeof(*p));printf(%d\n, sizeof(p[0]));printf(%d\n, sizeof(p));printf(%d\n, sizeof(p 1));printf(%d\n, sizeof(p[0] 1));return 0;
}p 是一个字符指针指向的是一个常量字符串
sizeof§, p 是一个指针变量也就是地址4/8 个字节
sizeof(p1), p 1 跳过一个元素指向第二个元素还是一个地址4/8 个字节
sizeof(*p), *p 字符串首元素解引用取出 aa 是 char 类型1 个字节
sizeof(p[0]), p[0] 取出字符‘a’大小为 1 个字节
sizeof(p), p 取出的是 p 的地址是一个二级指针数据类型为 char** 也就是 4/8 个字节
sizeof(p1), p 1,取出 p 的地址是个二级指针数据类型为 char** 再跳过一个数组 还是一个地址 4/8 个字节
sizeof(p[0]1), p[0] 表明取出首元素的地址跳过一个元素指向第二个元素的地址也就是 ‘b’ 的地址还是一个地址4/8 个字节
看一下运行结果
代码六
#include stdio.h
#include string.hint main()
{char* p abcdef;printf(%d\n, strlen(p));printf(%d\n, strlen(p 1));printf(%d\n, strlen(*p));printf(%d\n, strlen(p[0]));printf(%d\n, strlen(p));printf(%d\n, strlen(p 1));printf(%d\n, strlen(p[0] 1));return 0;
}strlenp) 从第一个元素开始到 \0 结束就是6
strlen(p1), 从第一个元素开始1 跳过一个元素从第二个元素计算也就是 5
strlen(*p), *p 取出第一个元素不是地址系统报错硬要访问a的ascll码值是97访问的是地址编号为97这是属于操作系统的是不允许访问的
strlen(p[0]), p[0] 取出第一个元素不是地址系统报错硬要访问a的ascll码值是97访问的是地址编号为97这是属于操作系统的是不允许访问的
strlen(p), p 指向 p 的地址未知空间不知道何时遇到 \0 , 随机值
strlen(p1), p 取出 p 的地址 p1 跳过一个 char* , 未知空间随机值
strlen(p[0]1), p[0] 取出首元素的地址1 跳过一个元素指向第二个元素也就是 5
课外探讨p 和 p 1 有关系吗实际没有因为你不知道 p 内部是否有 \0 如果有他们的大小就是差 1 二维数组
首先我们来回顾一下二维数组二维数组可以看出一个个一维数组组成的举个例子 int arr [3][3] {1,2,3,4,5,6,7,8,9}; 我们可以将二位数组看成由一个又一个的一维数组组成则二维数组的首元素地址就是第一行的地址。
arr [0], arr[1], arr[2], 如果单独放在sizeof 内部的话分别表示 数组的第一行 第二行第三行的数组名否则就是代表数组第一行、第二行、第三行的首元素地址。
我们来看一下下面的题目
#include stdio.h
#include string.hint main()
{int a[3][4] { 0 };printf(%d\n, sizeof(a));printf(%d\n, sizeof(a[0][0]));printf(%d\n, sizeof(a[0]));printf(%d\n, sizeof(a[0] 1));printf(%d\n, sizeof(*(a[0] 1)));printf(%d\n, sizeof(a 1));printf(%d\n, sizeof(*(a 1)));printf(%d\n, sizeof(a[0] 1));printf(%d\n, sizeof(*(a[0] 1)));printf(%d\n, sizeof(*a));printf(%d\n, sizeof(a[3]));return 0;
}sizeof(a), a 单独放在sizeof 内部, 表示整个数组的大小3 * 4 * sizeof(int)) 48
sizeof(a[0][0]), a[0][0] 大小为 4 个字节
sizeof(a[0]), a[0] 单独放在 sizeof 内部表示第一行的数组大小 4 * 4 16
sizeof(a[0]1), a[0] 不是单独放在 sizeof 内部则表示的是第一行的首元素 也就是 a[0][0] 1 跳过一个元素指向 a[0][1] 的地址4/8 个字节
sizeof(*(a[0]1)) , a[0] 1 a[0][1], 解引用之后就是a[0][1], 也就是 4 个字节
sizeof(a1), a 再这里表示数组的首元素也就是第一行的地址1跳过一行就是第二行的地址地址就是 4/8 个字节
sizeof(*(a1)), a1 指向第二行的地址解引用后就是取出第二行的数组大小就是 4 * 4 16
sizeof(a[0]1), a[0] 取出第一行的地址 1 表示跳过一行指向第二行的地址4/8 个字节
sizeof(*a[0]1) , 解引用取出第二行也就是 4 * 4 16 个字节
sizeof(*a), a 表示数组首元素的地址第一行的地址解引用取出第一行大小为 4 * 4 16
sizeof(a[3]), a[3] 大小为 4 * 4 16 个字节为什么不会有越界的问题因为 sizeof 不参与计算a[3]无需真实存在仅仅通过类型的推断就能算出长度a[3] 表示第四行的数组名单独放在 sizeof 内部计算的是第四行的大小4 * 4 16
我们来看一下运行结果 指针运算笔试题解析
题目一
#include stdio.hint main()
{int a[5] { 1, 2, 3, 4, 5 };int* ptr (int*)(a 1);printf(%d,%d, *(a 1), *(ptr - 1));return 0;
}我们用图片和文字来双重解析一下 a表示数组首元素的地址1 跳过一个元素* (a1) 就是 取出 第二个元素 2 a 表示取出整个数组的元素 1 跳过一个数组 int* prt (int*)(a1)将a1 原先的数据类型int () [5]) 强制类型转化为 int ptr-1 要注意了是向后移动一个元素为什么呢因为 ptr 的类型是 int* , - 1 也就是向后移动 int最终指向 5
来看一下运行结果
题目二
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥#include stdio.hstruct 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;
}这里的0x1就是表示1 p的类型是 struct Test * 1表示跳过一个结构体也就是地址20由于0x是16进制所以20换成16 进制就是 0x14, 0x100000 0x14 0x100014
(unsigned long) p将 p 强制类型转换为 无符号的长整型1就是0x100001
(unsigned int*)p 将p 强制类型转换为 unsigned int*,1跳过 unsigned int 的字节大小也就是0x100000 0x4 0x100004
运行结果如下
题目三
#include stdio.hint main()
{int a[3][2] { (0, 1), (2, 3), (4, 5) };int* p;p a[0];printf(%d, p[0]);return 0;
}要注意了这是一个逗号表达式都好表达式的结果去最后一个值所以{012345} 的值应该为{135}
所以数组a[3][2]{1,3,5,0,0,0},pa[0]表示数组第一行的地址p[0]相当于a[0][0]也就是取出第一行的首元素也就是 1
运行结果如下
题目四
//假设环境是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 a[5][5],a 的类型是int()[5], 因为这是一个二维数组二维数组的首元素是二维数组的第一行所以a的类型是 int () [5] int (p)[4],无需置疑p的类型就是int ()[4]
那么a[4][2]就无需多讲p[4][2]其实就是*(*p4)2), p4表示跳过4个int [4],然后2 表示跳过2个int ,指向图如下图所示。
然后我们要知道指针 - 指针代表就是两个指针之间的元素个数所以p[4][2]-a[4][2] 之间有4个元素由于是低地址减去高地址所以是-4
%d打印有符号的整数就是-4 %p打印的是地址所以我们需要知道-4在内存中然后存储那就要将-4的补码写出来(-4的原码是10000000000000000000000000000100反码就是11111111111111111111111111111011补码就是11111111111111111111111111111100也由于是x86环境下所以是32位的地址于是将补码转换成16进制的数值也就是FFFFFFFC 运行结果
题目五
#include stdio.hint 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表示取出整个数组的地址1跳过一个数组然后强制类型转换为int*, 赋给ptr1 aa表示数组的首元素1跳过一个元素然后强制类型转换为int*, 赋给ptr2
ptr-1 由于ptr 是int*类型所以跳过一个int 同理ptr2-1也是跳过一个int 运行结果
题目六
#include stdio.hint main()
{char* a[] { work,at,alibaba };char** pa a;pa;printf(%s\n, *pa);return 0;
}a是个字符指针数组存放的是work,at,alibaba的首元素的地址 pa a意味着pa是a的首元素的地址pa跳过一个char*也就是指向a 的第二个元素*pa 取出a的第二个元素也就是at的首元素的地址所以打印at 运行结果
题目七
#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;
}我们先将图画出来 在这里的优先级最低
** cpp cpp先指向c2的地址解引用取出c2再解引用取出POINT的地址
*--*cpp3 首先cpp在上面已经自增过一次再之后cpp就指向c1的地址解引用取出c1然后c1再–变成c再解引用就会取出ENTER的地址然后3跳过三个元素也就是指向E的地址打印出ER
现在cpp是指向cp第三个元素的地址
cpp[-2]3,我们先来解读cpp[-2],cpp[-2]表示(cpp-2),也就是取出c3的地址*cpp[-2]解引用取出FIRST的地址3跳过三个元素也就是指向S的地址打印出ST
cpp[-1][-1],我们来分解一下*( *( cpp-1 )-1 ),cpp-1指向cp第二个元素的地址解引用取出c2, c2-1c1, 解引用一下就取出NEW的地址最后cpp[-1][-1] 1 之后就是指向E的地址也就是打印出EW
运行结果