C语言初级指针

#include <stdio.h>
#include <stdlib.h>
int main() {
    int a[] = { 1, 2, 3, 4 };
    printf("%d\n", sizeof(a));  // 求整个数组的字节数,4*4 = 16
    printf("%d\n", sizeof(a + 0));  // 此时数组名隐式退化成指针,在32位操作系统下是答案是4
    printf("%d\n", sizeof(*a));  // 取到了整数1,答案是4
    printf("%d\n", sizeof(a + 1));  // 也是指针,答案是4
    printf("%d\n", sizeof(a[1]));  // 整数2, 答案是4
    printf("%d\n", sizeof(&a));  // 数组指针,凡是指针都是4个字节
    printf("%d\n", sizeof(*&a));  // *和&是相反的操作,取到了整个数组元素,16个字节
    printf("%d\n", sizeof(&a + 1));  // 数组指针,4个字节
    printf("%d\n", sizeof(&a[0]));  // 此时是一个int*,4个字节
    system("pause");
    return 0;
}

①我们可以看到 a[] 是一个 int* 类型的数组,而数组名是不能和整数进行相加减的,一旦进行相加减则会隐式退化成指针,这个指针指向数组首元素的地址。凡是指针在32位系统下都是 4 个字节(本篇默认是 32 位操作系统,在 64 位操作系统下指针则是 8 个字节)。

②而 *a 这个操作呢是先取到了一个数组名,而数组名也是不能解引用的( * 是解引用操作符,是针对数组的,相当于获取到指针所指向的具体内容),一旦进行解引用操作,这里的数组名也会隐式退化成指针,指向数组首元素即得到了数字1的地址,然后解引用便得到了数字1,而数字1是个int类型,所以是4个字节。

③a[] 操作呢想必大家都很熟悉,根据索引取相应位置的元素,因为此时的数组是个int类型,所以 a[] 操作所得到的结果都是4个字节。

④&a 得到的是一个数组指针,在上一篇博客中已经验证过,数组指针肯定也是个指针,对数组指针进行加减操作也是数组指针,所以也是4个字节。

⑤比较难理解的就是 *&a 了,这里先对a取地址得到了一个数组指针,再对数组指针解引用,得到了整个数组元素。

⑥最后的那个 &a[0] 操作呢是先取到了0号元素是数字1,然后对数字1取地址是个int*,也就是指针,所以是4个字节,不过这个int*和数组指针虽说都是指针,但是是不同类型的指针,大家要加以区分。


#include <stdio.h>
#include <stdlib.h>
int main() {
    char a[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
    printf("%d\n", sizeof(a));  // 求整个数组的字节数,6
    printf("%d\n", sizeof(a + 0));  // 此时数组名隐式退化成指针,在32位操作系统下是答案是4
    printf("%d\n", sizeof(*a));  // 取到了字符a,答案是1
    printf("%d\n", sizeof(a[1]));  // 字符b, 答案是1
    printf("%d\n", sizeof(&a));  // 数组指针,凡是指针都是4个字节
    printf("%d\n", sizeof(&a + 1));  // 数组指针,4个字节
    printf("%d\n", sizeof(&a[0] + 1));  // 此时是一个char*,4个字节
    
    printf("%d\n", strlen(a));  // 未定义行为
    printf("%d\n", strlen(a + 0));  // 未定义行为
    printf("%d\n", strlen(*a));  // 编译出错,原因是*a得到的是一个char类型,而strlen的参数时一个char*,类型不匹配
    printf("%d\n", strlen(a[1]));  // 编译出错
    printf("%d\n", strlen(&a));  // 编译出错
    printf("%d\n", strlen(&a + 1));  // 未定义行为
    printf("%d\n", strlen(&a[0] + 1));  // 未定义行为
    system("pause");
    return 0;
}

①这里先讲一下字符数组和字符串的区别,首先在C语言中字符串(简称C风格字符串)确实是以字符数组的形式进行表示的,而且这个字符数组要以 '\0' 为结束标志,但是这样并不代表所有的字符数组都是字符串吧。上面这道题很显然是个字符数组,但是并不是字符串,所以它没有 '\0' 这个标记。

②接着再讲一下 strlen 这个函数,strlen 是针对C风格字符串求字符串长度的函数,所以strlen(a)和strlen(a + 0)都是未定义行为,因为编译器根本就找不到 '\0' 标记,找着找着数组下标就越界了,所以就成了未定义行为。

③strlen它的函数声明是这样的:size_t__cdecl strllen (const char*) ,这里我们可以看到参数 const char* 是个char*类型的指针吧,所以我们不难理解为什么上述的好多strlen操作都是编译出错,是因为类型不匹配。


#include <stdio.h>
#include <stdlib.h>
int main() {
    // 此时是个字符串,而C风格字符串就是以'\0'最结尾标志的
    char a[] = "abcdef";
    printf("%d\n", sizeof(a));  // 求整个数组的字节数,7
    printf("%d\n", sizeof(a + 0));  // 此时数组名隐式退化成指针,在32位操作系统下是答案是4
    printf("%d\n", sizeof(*a));  // 取到了字符a,答案是1
    printf("%d\n", sizeof(a[1]));  // 字符b, 答案是1
    printf("%d\n", sizeof(&a));  // 数组指针,凡是指针都是4个字节
    printf("%d\n", sizeof(&a + 1));  // 数组指针,4个字节
    printf("%d\n", sizeof(&a[0]));  // 此时是一个char*,4个字节
    
    printf("%d\n", strlen(a));  // 字符串的长度,6
    printf("%d\n", strlen(a + 0));  // 6
    printf("%d\n", strlen(*a));  // 编译出错,原因是*a得到的是一个char类型,而strlen的参数时一个char*,类型不匹配
    printf("%d\n", strlen(a[1]));  // 编译出错
    printf("%d\n", strlen(&a));  // 数组指针,指向数组首元素,要注意此时是strlen而不是sizeof,从第一个元素往后找直到'\0\为止,所以答案是6
    printf("%d\n", strlen(&a + 1));  // 此时是个数组指针,数组指针+1则数组下标越界,所以是未定义行为
    printf("%d\n", strlen(&a[0] + 1));  // &a[0] + 1相当于取到了字符b,往后数找'\0',因此答案是5
    system("pause");
    return 0;
}

①这里的 a[] 里的元素就是个字符串了。可能很多朋友对strlen和sizeof这两个操作还是有点困惑的,那么就先讲一下这两个的区别。我们前面说了strlen是针对字符串求长度的,我们又知道字符串是以 '\0' 为结尾标志的,那么既然是在求长度也就是元素个数,'\0' 就不会算在长度里面了。再说sizeof是在计算字节数,注意是字节数,那么计算字节数也就是说占有的内存空间,这样的话我们想一下这个操作势必要把 '\0' 计算在内了。

②前面的sizeof和上面的题目差别不大,大家可以仔细研究。

③strlen(*a)和strlen(a[1])这两个操作是取到了字符a和字符b,所以是类型不匹配,编译出错。

④要注意的是这里的strlen(&a)这儿是个数组指针,指向数组首元素,往后依次找 '\0' 很容易得到字符串的长度是6,所以答案就是6。

⑤而 strlen(&a + 1) 数组指针加1操作指向了数组的外面,所以是未定义行为。


#include <stdio.h>
#include <stdlib.h>
int main() {
    char* p = "abcdef";
    printf("%d\n", sizeof(p));  // p是个指针,凡是指针都是4个字节
    printf("%d\n", sizeof(p + 1));  // 指针+1操作还是个指针,4
    printf("%d\n", sizeof(*p));  // 取到了字符a,答案是1
    printf("%d\n", sizeof(p[0]));  // 字符b, 答案是1
    printf("%d\n", sizeof(&p));  // 二级指针,二级指针也是指针,4
    printf("%d\n", sizeof(&p + 1));  // 二级指针+1操作也是个二级指针,4个字节
    printf("%d\n", sizeof(&p[0] + 1));  // 此时是一个指向b的指针,4个字节
    
    printf("%d\n", strlen(p));  // 字符串的长度,6
    printf("%d\n", strlen(p + 1));  // 此时是指向b的指针,往后找'\0',5
    printf("%d\n", strlen(*p));  // 未定义行为,原因是*p得到的是一个char类型,而strlen的参数时一个char*,类型不匹配
    printf("%d\n", strlen(p[0]));  // 未定义行为
    printf("%d\n", strlen(&p));  // &p取到了一个二级指针,二级指针和char*类型不匹配
    printf("%d\n", strlen(&p + 1));  //  仍是个二级指针,未定义行为
    printf("%d\n", strlen(&p[0] + 1));  // 指向b的指针,5
    system("pause");
    return 0;
}

①很显然这里的 p 是个 char* 类型的指针,而前面的那三个都是数组,大家注意区分。

②p 本来就是个指针,对指针进行加减整数的操作就会使指针跳过一个当前所指向的元素,说到底还是个指针,所以仍然是4个字节。

③&p 这次得到的已经是个二级指针了,不过二级指针加减整数也是个二级指针,也是4个字节。

④sizeof(&p[0] + 1) 说先取到了p[0]是字符a,对字符a取地址是指向字符a的指针,然后指针向后移一位,是指向字符b的指针,凡是指针则一定是4个字节。若是strlen的话那往后数5个就找到了结束标记。

⑤*p, p[0] 都是取到了一个字符,类型不匹配导致编译报错。

⑥要注意的是这里的&p是个二级指针,而二级指针也是和char*类型不配,但是这里我们要和上述那个题目的&a数组指针要加以区分。

⑦&p +1 也还是指向了数组外部,未定义行为。


当然关于指针的用法还有很多,这里只是凤毛麟角,关于指针我们要深究的还有很多。但是通过这篇博客相信大家也是可以了解很多指针的比较不容易理解的用法的,对于 strlen 和 sizeof ,还有字符串以及字符数组要加以区分。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值