C语言----深入理解指针(5)(一)

简介: C语言----深入理解指针(5)

1.sizeof和strlen的对比

sizeof计算变量所占内存空间的大小的,单位是字节

sizeof只关注内存空间的大小,不在乎内存中方的什么数据

sizeof是操作符不是函数

sizeof会将\0算进去的

// sizeof计算变量所占内存空间的大小的,单位是字节
 
int main()
{
    int a = 10;
    printf("%d\n", sizeof(int));//输出结果是4
    printf("%d\n", sizeof(a));//输出结果是4
 
 
    int arr[10] = { 0 };
    printf("%d\n", sizeof(arr));//输出的结果是40
    return 0;
}//sizeof只管新占了多大的内存空间大小

那么strlen呢?

strlen是c语言里面的库函数,是函数

作用的求字符串长度的,只能针对字符串

strlen统计的是字符串\0之前的字符个数

只能指针字符串,求字符串长度

不能求整形数组的

strlen直到遇到\0,不然是不会停下来的

int main()
{
    char arr1[] = { 'a','b','c' };
    char arr2[] = "abc";//字符串末尾隐藏着一个\0
    printf("%zd\n", strlen(arr1));//15---往后找\0,直到找到\0才停止--那么这个15就是随机值
    printf("%zd\n", strlen(arr2));//3---\0前面有三个字符
 
 
    printf("%zd\n", sizeof(arr1));//3---只关乎arr1占了多大的空间
    printf("%zd\n", sizeof(arr2));//4---放了4个字符,包括\0,总共占了4个字节 
 
 
    //strlen是用来求字符串长度的,不能用来求整型数组
 
    return 0;
}

2.数组和指针笔试题解析

sizeof---一维数组

//恢复:数组名是数组首元素的地址
//但是有两个例外
//sizeof(数组名)
//&数组名
//除了这两种,其他的都是数组首元素的地址
int main()
{
    int a[] = { 1,2,3,4 };
    printf("%zd\n", sizeof(a));//16---4个元素,每个元素4个字节
    //数组名a单独放在sizeof内部,a表示的是整个数组,计算的是整个数组的大小,单位是字节
 
 
 
    printf("%zd\n", sizeof(a+0));//4
    //a是数组名,数组首元素的地址,a+0还是首元素的地址
    //a+i就是数组内下标为i的数组元素
    //这里的sizeof计算的是首元素地址的大小
 
    printf("%zd\n", sizeof(*a));//4
    //这里的a依然是首元素的地址,*a就是首元素,就是a[0]
    //因为arr[0]是一个整数,就是4个字节
 
 
    printf("%zd\n", sizeof(a+1));//4
    //因为数组名表示的是首元素的地址,那么首元素加1
    //就是下标为1的数字的地址,就是这个数组内第二个元素的地址
    //arr[1]的地址
    //这里计算的是地址的大小
 
 
 
    printf("%zd\n", sizeof(a[1]));//4
    //a[1]就是数组内第二个元素,就是4个字节的大小
 
 
 
    printf("%zd\n", sizeof(&a));//4
    //取出整个数组的地址
    //数组的地址也是一个地址啊,是地址就是4个字节的长度
 
 
    printf("%zd\n", sizeof(*&a));//16
    //取出a的地址,再进行解引用,就是整个数组,
    //*和&抵消了,就是整个数组
    // sizeof(*&a)==sizeof(a)
    //&a是数组的地址,类型是int(*)[4]---数组指针类型
    //那么*&a就是访问真个数组
 
 
 
    printf("%zd\n", sizeof(&a+1));//4
    //&a就是整个数组的地址,地址+1就是跳过整个数组后的那个地址,
    // 但是仍然是地址啊
    //是地址就是4个字节
 
 
 
    printf("%zd\n", sizeof(&a[0]));//4
    //arr[0]是数组首元素的地址,再将其取出
    //取出数组首元素的地址
 
 
 
 
    printf("%zd\n", sizeof(&a[0]+1));//4
    //将首元素的地址取出,再+1就是第二个元素的地址
 
 
    return 0;
}

sizeof--字符数组

int main()
{
    char arr[] = { 'a','b','c','d','e','f' };//没有\0
    printf("%d\n", sizeof(arr));//6
    //整个数组的大小,6个字符就是6
 
    printf("%d\n", sizeof(arr+0));//4
    //arr是首元素的地址,arr+0还是首元素的地址,地址的字节就是4
 
 
    printf("%d\n", sizeof(*arr));//1
    //对数组首元素地址进行解引用就是数组首元素,字符就是1个字节
    printf("%d\n", sizeof(arr[1]));//1
    //数组中下标为1的字符,大小是1个字节
 
 
 
    printf("%d\n", sizeof(&arr));//4
    //取出整个数组的地址,仍然是地址,地址就是4个字节的大小
 
 
    printf("%d\n", sizeof(&arr+1));//4
    //取出整个数组的地址,+1跳过整个数组,还是地址,就是4个字节的大小
 
    printf("%d\n", sizeof(&arr[0]+1));//4
    //取出数组首元素的地址,再+1就是第二个元素的地址,地址是4个字节大小
 
 
    return 0;
}

strlen---大括号--一堆字符

int main()
{
    char arr[] = { 'a','b','c','d','e','f' };//没有\0
    printf("%zd\n", strlen(arr));//随机值
    //这里的arr表示的是首元素的地址
    //从首元素开始数字符,一直数到\0之前才停止
    //那么这里的值就是随机值
 
    printf("%zd\n", strlen(arr+0));
    //arr+0还是数组名-----首元素的地址
    //那么返回的值就是随机值,这个代码和上面的代码没有区别
    //并且这两个随机值是一样的
 
 
    printf("%zd\n", strlen(*arr));
    //arr是首元素的地址,那么对其进行解引用就是数组第一个元素,就是'a'字符
    //strlen(a)---'a'的ASCII的大小是97,strlen不能运行
    //a的值传递给strlen,strlen会认为97是地址,然后会访问内存
    //这个代码是有问题的
 
 
    printf("%zd\n", strlen(arr[1]));
    //arr[1]是数组下标为1的元素
    //strlen('b')---'b'的ASCII大小是98
    //这个程序也会崩溃
 
    printf("%zd\n", strlen(&arr));//随机值
    //将数组的整个数组的地址传过去了
    //strlen依然从首元素往后数
    //依然没有遇到\0
    //那么返回值就是随机值
 
    //&arr的类型是----char(*)[6]
 
    printf("%zd\n", strlen(&arr+1));//随机值
    //取出整个数字的地址,然后+1跳过整个数组
    //也是随机值,不知道什么时候遇到\0
 
 
 
    printf("%zd\n", strlen(&arr[0]+1));//随机值
    //arr[0]是数组首元素,+1就是b,那么strlen往后直到遇到\0才停止,那么
    //这个代码返回的也是随机值
 
 
 
 
    return 0;
}

sizeof--字符串

//数组名是数组首元素的地址
//两个例外:
//sizeof(arr)
//&arr---这里的数组名表示整个数组,取出的是数组的地址
 
int main()
{
    char arr[] = "abcdef";//字符串初始化
    //这个字符串末尾还有一个\0
    printf("%zd\n", sizeof(arr));//7
    //arr作为数组名,这里计算的是这个数组的大小
    //一个字符一个字节,那么这里就是7个字节
    //这里的数组名是单独的放在sizeof里面的
 
 
    printf("%zd\n", sizeof(arr + 0));//4
    //数组名--就是数组首元素的地址
    //这里的arr并不是单独的放在sizeof里面
    //那么这里的arr+0是首元素的地址
    //既然是地址,那么大小就是4个字节
 
 
 
    printf("%zd\n", sizeof(*arr));//1
    //这里的arr是数组名--首元素的地址
    //对arr进行解引用达到的就是首元素
    //首元素的大小是1个字节--每个字符的大小是1个字节
 
 
 
    printf("%zd\n", sizeof(arr[1]));//1
    //数组下标为1的元素,字符,所以大小也是1
 
 
    printf("%zd\n", sizeof(&arr));//4
    //取出整个数组的地址,地址就是4个字节
 
 
 
    printf("%zd\n", sizeof(&arr + 1));//4
    //取出的是整个数组的地址,再+1,得到的就是跳过整个数组
    //得到的也是地址,既然是地址就是4个字节的大小
 
 
 
 
    printf("%zd\n", sizeof(&arr[0] + 1));//4
    //arr[0]是数组首元素,取出数组首元素的地址再+1
    //得到的就是数组内的第二元素的地址,地址就是4个字节大小
    //首元素的地址类型是char*
 
 
    return 0;
}

strlen---字符串

int main()
{
    char arr[] = "abcdef";//字符串末尾放着\0的
    printf("%d\n", strlen(arr));//6
    //这里的arr是首元素的地址
    // 从首元素开始数,数到\0之前就停止
    //strlen是求字符串长度的
    //因为末尾放着一个\0,那么strlen数的就是\0前面的字符个数
    //strlen是从第一个元素开始统计\0之前的字符个数
 
 
    printf("%d\n", strlen(arr + 0));//6
    //arr是首元素的地址,那么arr+0还是首元素的地址
    //那么把数组首元素的地址传给strlen,就是从首元素开始统计,直到遇到\0
 
 
 
    printf("%d\n", strlen(*arr));
    //arr是首元素的地址,那么解引用得到的就是首元素字符'a'
    //'a'的大小是97,将97当成地址传递给strlen,97这个地址不能被访问,这个程序就崩溃了
 
 
 
    printf("%d\n", strlen(arr[1]));
    //arr[1]是数组下标为1的元素,第二个元素,访问的是'b'
    //这个代码的道理和上面的一样,一样会崩溃的
 
 
    printf("%d\n", strlen(&arr));//6
    //取出数组的地址,将取出的地址存放至数组指针变量里面这么写
    //char(*pa)[7]=&arr
//那么pa的类型是char(*)[7]
    //但是对于strlen这个库函数来说
    //size_t strlen (const char* str)
    //硬要将char(*)[7]这个地址传过去,因为char(*)[7]与const char* str不一致,会导致将传过来的指向强制转换为strlen所需要的类型
    //
    //数组的地址和数组首元素的地址是指向同一个位置的
    //那么strlen也是从第一个元素的位置开始向后访问
    //所以这个代码实现的数据是6
 
    printf("%d\n", strlen(&arr + 1));//随机值
     //取出数组的地址,再+1就是跳过整个数组,那么strlen遇到\0才会停止
    //那么这里的就是随机值
 
 
    printf("%d\n", strlen(&arr[0] + 1));//5
    //取出的是首元素的地址,那么首元素的地址+1就是数组第二个元素的地址
    //那么strlen就从第二个元素开始访问进行统计的
    //那么这里的 数据就是5
    return 0;
}
//在这些代码运行的时候
//会出现很多警告
//因为我们在传参的时候类型不一致
//&arr的类型是char(*)[7],而strlen只能接受const char* str这个类型的指针

sizeof---指针

int main()
{
    char* p = "abcdef";//将首字符的地址存放在p中
    printf("%zd\n", sizeof(p));//4
    //p是指针变量。那么sizeof(p)计算的就是指针变量p的大小
    //因为一个指针变量的大小是4个字节--x86的情况下,x64的情况下是8个字节
 
 
 
    printf("%zd\n", sizeof(p + 1));//4
    //p存的是首元素的地址,p的类型是char*
    //那么p+1得到的是b的地址,就是相当于跳过了一个字符
    //地址的大小就是4个字节
 
 
 
    printf("%zd\n", sizeof(*p));//1
    //p是字符串首元素的地址,对p进行解引用,得到的就是首元素,首元素是字符a
    //a的字节大小是1
    //因为p的类型是char*,只能访问一个字节,就是a
 
 
 
 
    printf("%zd\n", sizeof(p[0]));//1
    //p[0]-->*(p+0)---得到的就是字符a---大小为1个字节
 
 
 
    printf("%zd\n", sizeof(&p));//4
    //取出p的地址,&p是p的地址,对p的地址进行大小计算,地址的大小就是4个字节
 
 
 
    printf("%zd\n", sizeof(&p + 1));//4
    //取出p的地址进行+1操作
    // 
    // 
    // char* *ptr=&p       ptr指向的p是一个类型为char*类型的指针,后面的*说明ptr是一个指针
    //&p的指针类型是char * *,对&p+1就是跳过一个char* * 类型的对象
 
 
    //举例:int *p   对p+1跳过的就是一个整型对象
 
 
    //&p是p的地址,&p+1是跳过了p变量,指向了p的后面
    //因为&p+1是地址,就是4个字节
 
    printf("%zd\n", sizeof(&p[0] + 1));//4
    //p[0]是*(p+0)---就是首元素a
    //前面加上&得到的就是a的地址,+1就是b的地址
 
    //&p[0]就是p
 
 
 
 
    return 0;
}

strlen---指针

int main()
{
    char* p = "abcdef";//将这个字符串首元素的地址存储在p中,末尾有\0
 
 
    printf("%zd\n", strlen(p));//6
    //p里面放的是a的地址,
    //strlen(p)就是从a的地址开始统计这个字符串的长度
    //得到的数据是6
 
 
    printf("%zd\n", strlen(p + 1));//5
    //p存的是a的地址,因为p是char*的指针,那么p+1就是指向b的地址
    //就是从b的地址位置开始统计这个字符串的个数
    //那么得到的数据就是5
 
 
 
    printf("%zd\n", strlen(*p));//程序崩溃
    //*p是a,a是97
    //将97作为地址传给strlen,程序会崩溃的
 
 
    printf("%zd\n", strlen(p[0]));//程序崩溃
    //p[0]--->*(p+0)----*p---a----97
    //那么这个程序就会崩溃的
 
 
    printf("%zd\n", strlen(&p));//随机值
    //取出指针变量p的地址,那么strlen就从指针变量p地址开始统计,在p这块空间进行统计
    //那么得到的就是随机值
 
 
 
 
    printf("%zd\n", strlen(&p + 1));//随机值
    //&p是指针p的地址,+1就是跳过p的地址,开始进行统计
    //所以数据就是随机值
 
 
    printf("%zd\n", strlen(&p[0] + 1));//5
    //p[0]--->*(p+0)----*p---a
    //那么&p[0]就相当于p,
    //p里面存的是a的地址,+1得到的是b的地址
    //那么我们就从b的位置开始统计
    //得到的数据是5
 
 
 
    return 0;
}
//注意:p[0]--->*(p+0)----*p---a


C语言----深入理解指针(5)(二)https://developer.aliyun.com/article/1544408

相关文章
|
2月前
|
存储 C语言
【C语言篇】深入理解指针3(附转移表源码)
【C语言篇】深入理解指针3(附转移表源码)
40 1
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
51 0
|
5天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
2月前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
20 2
|
2月前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
2月前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
2月前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
2月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
2月前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
2月前
|
C语言
C语言指针(3)
C语言指针(3)
14 1