ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

C语言梦开始的地方12:指针终章

C语言梦开始的地方12:指针终章 文章目录C语言梦开始的地方12指针终章sizeof 和 strlen的对比sizeofstrlensizeof 和 strlen的对比数组 和 指针题目解析一维数组字符数组字符数组字符串字符指针二维数组指针运算题解析C语言梦开始的地方12指针终章sizeof 和 strlen的对比sizeof在了解C语言的操作符的时候我们了解了sizeof sizeof 计算变量所占内存内存空间大小的单位是字节如果操作数是类型的话计算的是使用类型创建的变量所占内存空间的大小。sizeof 只关注占用内存空间的大小不在乎内存中存放什么数据。比如#includestdio.hintmain(){inta10;printf(%d\n,sizeof(a));printf(%d\n,sizeofa);printf(%d\n,sizeof(int));return0;}strlenstrlen是C语言的库函数功能是求字符串长度。函数原型如下#includestring.h// 头文件size_tstrlen(constchar*str);统计的是从strlen 函数的参数str 中这个地址开始向后 \0 之前字符串中字符的个数。strlen 函数会一直向后找\0 字符直到找到为止所以可能存在越界查找。#includestdio.h#includestring.hintmain(){chararr1[3]{a,b,c};chararr2[]abc;printf(%d\n,strlen(arr1));printf(%d\n,strlen(arr2));printf(%d\n,sizeof(arr1));printf(%d\n,sizeof(arr2));}strlen(arr1)arr1是字符数组并且没有显示的写\0那么strlen在计算arr1时的结果是一个错误的大小但是这个结果一定是大于3的strlen(arr2)arr2是字符串字符串有个小知识点就是字符串末尾不写\0编译器自动补充所以这里计算的结果为3sizeof(arr1)arr1是char类型的数组char类型的大小是1字节arr1中有三个元素所以计算结果为3sizeof(arr2)arr2和arr1同理但是arr2是存字符串字符串我们通过strlen(arr2)时就了解了字符串末尾自带\0所以arr2实际上是4个字节sizeof 和 strlen的对比通过上面的了解我们能得出一下结论sizeofstrlen本质操作符关键字编译期求值C 标准库函数运行时调用头文件无需包含需要包含string.h参数类型类型名、变量名、表达式不实际求值必须是以\0结尾的字符串指针const char*计算内容对象或类型所占的内存字节数从起始地址到第一个\0之前的字符个数是否包含末尾\0若是数组包含整个数组的大小包括可能存在的\0不包含\0安全性不访问内存内容仅根据类型推导安全可能越界访问若字符串没有\0终止符会一直向后查找返回值类型size_t无符号整数size_t无符号整数适用场景获取变量/类型的内存容量常用于内存分配、数组大小计算获取字符串有效长度用于字符串处理、遍历等对数组名的处理返回整个数组的字节数不退化数组名退化为指向首元素的指针返回从首元素到\0的字符数对指针变量的处理返回指针本身的大小4 或 8 字节与指向内容无关返回指针所指字符串的长度需要指针指向有效字符串数组 和 指针题目解析经过对数组和指针了解我们来做几道题来深入了解一下数组和指针吧一维数组#includestdio.h#includestring.hintmain(){inta[]{1,2,3,4};printf(%d\n,sizeof(a));printf(%d\n,sizeof(a0));printf(%d\n,sizeof(*a));printf(%d\n,sizeof(a1));printf(%d\n,sizeof(a[1]));printf(%d\n,sizeof(a));printf(%d\n,sizeof(*a));printf(%d\n,sizeof(a1));printf(%d\n,sizeof(a[0]));printf(%d\n,sizeof(a[0]1));return0;}sizeof(a) - 整个数组大小4*416。sizeof(a0) - a0是首元素地址指针所以sizeof指针864位。sizeof(*a) - *a是首元素int4。sizeof(a1) - 指针8。sizeof(a[1]) - 第二个元素int4。sizeof(a) - a是数组指针int(*)[4]但仍是指针8。sizeof(*a) - *a相当于a所以是数组16。sizeof(a1) - a1是指针跳过整个数组仍是指针8。sizeof(a[0]) - 指向首元素的指针8。sizeof(a[0]1) - 指针8。字符数组字符数组#includestdio.h#includestring.hintmain(){chararr[]{a,b,c,d,e,f};printf(%d\n,sizeof(arr));printf(%d\n,sizeof(arr0));printf(%d\n,sizeof(*arr));printf(%d\n,sizeof(arr[1]));printf(%d\n,sizeof(arr));printf(%d\n,sizeof(arr1));printf(%d\n,sizeof(arr[0]1));printf(%d\n,strlen(arr));printf(%d\n,strlen(arr0));printf(%d\n,strlen(*arr));printf(%d\n,strlen(arr[1]));printf(%d\n,strlen(arr));printf(%d\n,strlen(arr1));printf(%d\n,strlen(arr[0]1));return0;}sizeof(arr) - 整个数组大小6 个 char6 字节。sizeof(arr0) - arr0 是首元素地址指针64 位下 8 字节。sizeof(*arr) - *arr 是首元素 ‘a’char 类型1 字节。sizeof(arr[1]) - arr[1] 是第二个字符char1 字节。sizeof(arr) - arr 是数组指针char(*)[6]但仍是指针8 字节。sizeof(arr1) - arr1 是指针跳过整个数组仍是指针8 字节。sizeof(arr[0]1) - arr[0]1 指向第二个元素指针8 字节。strlen(arr) - 数组无 ‘\0’从首元素开始越界查找结果未定义通常 6。strlen(arr0) - 同 strlen(arr)未定义。strlen(*arr) - 错误*arr 是 charASCII 97被当作地址传入野指针访问。strlen(arr[1]) - 错误arr[1] 是 char98同 10危险。strlen(arr) - arr 地址与 arr 相同仍从首元素起查找未定义同 8。strlen(arr1) - 地址跳过整个数组从未知位置开始找 ‘\0’大概率崩溃或随机值。strlen(arr[0]1) - 从第二个元素 ‘b’ 开始查找数组无 ‘\0’未定义通常 5。字符串#includestdio.h#includestring.hintmain(){chararr[]abcdef;printf(%d\n,sizeof(arr));printf(%d\n,sizeof(arr0));printf(%d\n,sizeof(*arr));printf(%d\n,sizeof(arr[1]));printf(%d\n,sizeof(arr));printf(%d\n,sizeof(arr1));printf(%d\n,sizeof(arr[0]1));printf(%d\n,strlen(arr));printf(%d\n,strlen(arr0));printf(%d\n,strlen(*arr));printf(%d\n,strlen(arr[1]));printf(%d\n,strlen(arr));printf(%d\n,strlen(arr1));printf(%d\n,strlen(arr[0]1));return0;}sizeof(arr) - 整个数组大小字符串 “abcdef” 包含末尾 ‘\0’共 7 个 char7 字节。sizeof(arr0) - arr0 是首元素地址指针64 位下 8 字节。sizeof(*arr) - *arr 是首字符 ‘a’char 类型1 字节。sizeof(arr[1]) - arr[1] 是第二个字符 ‘b’char1 字节。sizeof(arr) - arr 是数组指针char(*)[7]但仍是指针8 字节。sizeof(arr1) - arr1 是指针跳过整个数组 7 字节仍是指针8 字节。sizeof(arr[0]1) - arr[0]1 指向第二个元素指针8 字节。strlen(arr) - 从首字符 ‘a’ 到 ‘\0’ 共 6 个字符不包含 ‘\0’结果为 6。strlen(arr0) - 同 strlen(arr)结果为 6。strlen(*arr) - 错误*arr 是 charASCII 97被当作地址传入野指针访问行为未定义。strlen(arr[1]) - 错误arr[1] 是 char98同 10危险。strlen(arr) - arr 的地址与 arr 相同从首元素起查找结果为 6。strlen(arr1) - 地址跳过整个数组指向数组后的未知内存未找到 ‘\0’ 前会越界结果未定义随机值或崩溃。strlen(arr[0]1) - 从第二个字符 ‘b’ 开始到 ‘\0’共 5 个字符结果为 5。字符指针#includestdio.h#includestring.hintmain(){char*pabcdef;printf(%d\n,sizeof(p));printf(%d\n,sizeof(p1));printf(%d\n,sizeof(*p));printf(%d\n,sizeof(p[0]));printf(%d\n,sizeof(p));printf(%d\n,sizeof(p1));printf(%d\n,sizeof(p[0]1));printf(%d\n,strlen(p));printf(%d\n,strlen(p1));printf(%d\n,strlen(*p));printf(%d\n,strlen(p[0]));printf(%d\n,strlen(p));printf(%d\n,strlen(p1));printf(%d\n,strlen(p[0]1));}sizeof§ - p 是指针64 位下 8 字节。sizeof(p1) - p1 仍是指针char*8 字节。sizeof(*p) - *p 是字符 ‘a’char 类型1 字节。sizeof(p[0]) - p[0] 等价于 *(p0)字符1 字节。sizeof(p) - p 是 char** 类型指向指针的指针仍为指针8 字节。sizeof(p1) - p1 仍是 char** 指针8 字节。sizeof(p[0]1) - p[0]1 指向第二个字符的地址char*指针8 字节。strlen§ - p 指向字符串 “abcdef”有效长度 6不含 ‘\0’。strlen(p1) - p1 指向 “bcdef”长度为 5。strlen(*p) - 错误*p 是字符 ‘a’ASCII 97被当作地址传入野指针访问行为未定义。strlen(p[0]) - 错误p[0] 也是字符 ‘a’同 ⑩未定义。strlen(p) - p 是指向指针变量 p 的地址该内存中存储的是地址值非字符串strlen 会将其误读为字符串结果未定义通常随机或崩溃。strlen(p1) - p1 指向 p 变量之后的内存更不确定未定义。strlen(p[0]1) - p[0]1 指向字符 ‘b’从 ‘b’ 到 ‘\0’ 共 5 个字符结果为 5。二维数组#includestdio.hintmain(){inta[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(a1));printf(%d\n,sizeof(*(a1)));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]));return0;}sizeof(a) - 整个二维数组大小3 行 × 4 列 × 4 字节 48 字节。sizeof(a[0][0]) - 首元素int 类型4 字节。sizeof(a[0]) - a[0] 是第一行数组int[4]在 sizeof 中不退化大小为 4×416 字节。sizeof(a[0] 1) - a[0] 退化为指向首元素的指针int*1 指向第二个元素仍为 int*指针大小 8 字节64 位。sizeof((a[0] 1)) - 解引用 int得到 int4 字节。sizeof(a 1) - a 退化为指向第一行的指针int(*)[4]1 指向第二行仍为指针8 字节。sizeof(*(a 1)) - 解引用得到 int[4]在 sizeof 中不退化大小为 16 字节。sizeof(a[0] 1) - a[0] 是 int(*)[4] 类型1 指向第二行仍为指针8 字节。sizeof(*(a[0] 1)) - 解引用得到 int[4]大小为 16 字节。sizeof(*a) - *a 是第一行类型 int[4]大小为 16 字节。sizeof(a[3]) - a[3] 是 int[4] 类型尽管越界sizeof 只根据类型求值不访问实际内存所以大小仍为 16 字节。指针运算题解析指针运算主要包括指针 - 整数、指针 - 指针、指针比较。#includestdio.hintmain(){inta[5]{1,2,3,4,5};int*ptr(int*)(a1);printf(%d,%d,*(a1),*(ptr-1));return0;}a 是整个数组的地址a1 跳过整个数组5个int指向数组之后的内存。强制转为 int*所以 ptr 指向数组末尾之后。*(a1) 是 a[1] 2。*(ptr-1) 指针向前移动一个 int指向最后一个元素 a[4] 5。输出2 5#includestdio.hintmain(){char*c[]{ENTER,NEW,POINT,FIRST};char**cp[]{c3,c2,c1,c};char***cppcp;printf(%s\n,**cpp);printf(%s\n,*--*cpp3);printf(%s\n,*cpp[-2]3);printf(%s\n,cpp[-1][-1]1);return0;}**cppcpp 先自增指向 cp[1]即 c2解引用得到 c[2]再解引用得到 “POINT”。输出 POINT。–cpp3cpp 指向 cp[1]值为 c2cpp → cpp 指向 cp[2]值为 c1cpp → 得到 c1即 c[1]-- → 对 c1 自减变为 c即 c[0]→ 解引用 c得到 c[0]即字符串 “ENTER” 的首地址3 → 从 “ENTER” 首地址偏移 3 个字符指向索引 3 的字符 ‘E’。输出ER*cpp[-2]3注意 cpp 当前指向 cp[2]cpp[-2] 等价于 *(cpp-2)即 cp[0]值为 c3。解引用得到 c[3] 即 “FIRST” 的首地址3 指向索引3 ‘S’输出 “ST”。cpp[-1][-1]1当前 cpp 指向 cp[2]cpp[-1] 是 cp[1]值为 c2再 [-1] 即 (c2)[-1] 等价于 *(c2 -1) *(c1) c[1]即 “NEW” 的首地址1 指向 ‘E’输出 “EW”。最终输出POINT ER ST EWC语言的指针篇章终于结束了下一章我们将深入C语言了解字符和字符串的知识与函数完
返回列表