深入了解指针和数组

简介: 深入了解指针和数组

一、sizeof和strlen

1.sizeof 操作符

sizeof实际上是一个操作符:

sizeof(表达式),表达式不参与运算,sizeof计算的是表达式最终占空间的字节的大小,计算的是字节,表达式也可以是某个变量的类型

sizeof计算的是表达式所占字节的大小

int a = 0;
printf("%d\n",sizeof(a));//这里sizeof计算的是a的大小是4个字节
printf("%d\n",sizeof(int));//这里sizeof计算的是一个整型的大小是4个字节

sizeof(表达式),表达式不参与运算

int a = 5;
int c = 10;
printf("%d\n",sizeof(c = a + 1));//这里sizeof计算的是c的大小,c是一个整数,占4个字节
//c在sizeof内部表达式中被赋给了a+1的值,但sizeof中的表达式是不参与运算的
printf("%d\n",c);//最终打印出的c的值还是10

2.strlen库函数

strlen是c语言库中自带的库函数:

strlen本质上是判断字符串的长度,传给strlen一段字符串,strlen会计算字符串中’\0’前有多少个字符来计算整个字符串的长度,其中空格也会被计算。

它的关键是找字符串中的’\0’,如果没有找到,他就会越界,直到找到’\0’为止,此时他就会返回一个随机值



举个栗子:

strlen使用方式:

char arr1[20] = "I am strlen!";//字母、空格、符号总共加起来有12个字符,
                               //这个字符串长度为12
printf("%d\n",strlen(arr1));//通过strlen打印出来的结果也是12

找不到‘\0’时:

char arr[] = { 'a','b','c','d','e','f' };//这是一个字符数组,存放了6个字符,没有'\0'
printf("%d\n", strlen(arr));//这时如果想要通过strlen计算长度,
//它会从第一个元素的地址开始计算,找到数组最后一个字符时,仍然没有找到'\0',
//它会继续往后找,直到找到'\0',返回的就是一个随机值

二、sizeof和数组的联系


数组名的意义

只有当sizeof(数组名)和&数组名,数组名表示整个数组,其他任何出现数组名的地方都表示数组首元素地址。


在这里深入了解一下sizeof和数组结合后会有哪些不同的意义:

1.sizeof(数组名),这里的数组名表示的是计算整个数组的大小

2.sizeof(数组名+数字),这里的数组名是数组首元素的地址,sizeof计算的是数组下标为该数字的地址,而地址就是指针的大小,根据不同的编译器(x86/x64)下,最终结果为4/8

3.sizeof(&数组名),数组名前加了取地址运算符,这个数组就表示整个数组,取出的也是整个数组的地址,是地址就是指针类型,返回的就是4/8。


三、指针和数组的一些练习

1.一维数组

下面每个数组都是基于如下一维数组a

int a[] = { 1,2,3,4 };

subject_1:

printf("%d\n", sizeof(a));//输出为16


sizeof(数组名),数组名表示整个数组的大小,这里计算的就是整个数组的大小占多少字节

数组中每个元素都是整型,也就是每个元素都占4个字节,总共4个元素,占4*4=16个字节

subject_2:

printf("%d\n", sizeof(a + 0));//输出为4/8


sizeof(a+0),中a表示数组首元素地址,+0后还是数组首元素地址,地址计算出的就是4/8个字节。

subject_3:

printf("%d\n", sizeof(*a));//输出为4,表示一个整数的大小是4个字节


数组a没有单独和sizeof放一块,a表示数组首元素地址,而*a就是对数组首元素地址进行解引用,得到的是数组的第一个元素1,1是整型,所以它的大小就是4个字节。

subject_4:

printf("%d\n", sizeof(a + 1));//输出为4/8


数组a没有和sizeof单独放一块,a表示数组首元素地址,a+1表示的就是数组下标为1的地址,sizeof(a+1)计算的是地址的大小,为4/8个字节。

subject_5:

printf("%d\n", sizeof(a[1]));//输出为4


很明显,a[1]就是数组第二个元素,sizeof(a[1])就是sizeof(2),大小是4个字节。

subject_6:

printf("%d\n", sizeof(&a));//输出为4/8


这里对数组进行了&操作,a就表示整个数组,取出的也是整个数组的地址,sizeof计算的就是整个数组的地址的大小,为4/8个字节。

subject_7:

printf("%d\n", sizeof(*&a));//输出为16


数组a首先进行&操作,取出了整个数组的地址,然后对该地址进行解引用操作,最终得到的就是整个数组的元素,sizeof(*&a)计算的是数组a中全部元素的大小,应为4 * 4 = 16个字节。

subject_8:

printf("%d\n", sizeof(&a + 1));//输出为4/8


数组a首先进行&操作,取出了整个数组的地址,然后进行+1跳过的就是整个数组,最终指向的是相当于整个数组的地址,sizeof(&a+1)计算的就是整个数组的地址,为4/8个字节。

subject_9:

printf("%d\n", sizeof(&a[0]));//输出为4/8


这里可以看出计算的是a[0]的地址的大小,也就是数组的第一个元素的地址的大小,是地址,结果就是4/8个字节。

subject_10:

printf("%d\n", sizeof(&a[0] + 1));//输出为4/8


先对a[0]进行&操作,得到第一个元素的地址,然后进行+1得到的就是第二个元素的地址,sizeof(&a[0]+1)计算的就是第二个元素的地址的大小就是4/8个字节。


2.字符数组

(1)sizeof与字符数组

sizeof计算的是占多大的字节

以下每个数组都是基于如下字符数组:

char arr[] = { 'a','b','c','d','e','f' };

subject_1:

printf("%d\n", sizeof(arr));//输出为6


arr数组名单独与sizeof放一块,表示整个数组的大小,计算的是整个数组的大小,其中1个字符为1个字节,共6个字符,大小就是6 * 1 = 6个字节。

subject_2:

printf("%d\n", sizeof(arr + 0));//输出为4/8


arr数组没有跟sizeof单独放一块,表示的就是数组首元素地址,+0操作后还是首元素地址,地址的大小就是4/8个字节。

subject_3:

printf("%d\n", sizeof(*arr));//输出为1


这里对arr进行解引用,arr表示的是数组首元素地址,解引用后就是数组首元素‘a’,sizeof(*arr)计算的是字符‘a’的大小,为1个字节。

subject_4:

printf("%d\n", sizeof(arr[1]));//输出为1


arr[1]就是数组第二个元素,sizeof(arr[1])计算的是字符’b’的大小,为1个字节。

subject_5:

printf("%d\n", sizeof(&arr));//输出为4/8


arr进行&操作,拿到的是整个数组的地址,sizeof(&arr)计算的就是数组的整个地址的大小,为4/8个字节。

subject_6:

printf("%d\n", sizeof(&arr + 1));//输出为4/8


&arr取出的是整个数组的地址,+1操作后跳过的是整个数组,指向的还是一个地址,这个地址也是相当于整个数组的地址。

subject_7:

printf("%d\n", sizeof(&arr[0] + 1));//输出为4/8


首先&arr[0]得到的是arr[0]的地址,就是第一个元素的地址,+1跳过一个元素的大小,指向了第二个元素的地址,sizeof(&arr[0]+1)计算的是第二个元素的地址的大小,为4/8个字节。


以下每个数组都是基于如下数组字符串:

char arr[] = "abcdef";

subject_1:

printf("%d\n", sizeof(arr));//输出为7


sizeof单独与arr放一块,计算的是整个数组的大小,数组中存放的是"abcdef\0",加上’\0’在内共有7个字符的字符串,它所占的大小就是7个字节。

subject_2:

printf("%d\n", sizeof(arr + 0));//输出为4/8


arr没有跟sizeof单独放一块,所以这里的arr+0拿到的就是数组首元素的地址,计算的也是数组首元素地址的大小为4/8个字节。

subject_3:

printf("%d\n", sizeof(*arr));//输出为1


arr没有跟sizeof单独放一块,arr表示数组首元素地址,解引用后就是数组第一个元素,sizeof(*arr)计算的是第一个数组元素的的大小为1个字节。

subject_4:

printf("%d\n", sizeof(arr[1]));//输出为1


arr[1]就是数组第二个元素,它的大小就是1个字节

subject_5:

printf("%d\n", sizeof(&arr));//输出为4/8


arr进行&操作得到整个数组的地址,sizeof(&arr)计算的是整个数组的地址的大小为4/8个字节。

subject_6:

printf("%d\n", sizeof(&arr + 1));//输出为4/8


arr先进行&操作得到整个数组的地址,然后+1跳过整个数组,指向下一个地址,sizeof(&arr+1)计算的是整个数组地址的大小为4/8个字节。

subject_7:

printf("%d\n", sizeof(&arr[0] + 1));//输出为4/8


arr[0]是第一个元素,对它&操作后得到第一个元素的地址,再+1得到了第二个元素的地址,sizeof(&arr[0]+1)计算的是第二个元素的地址的大小为4/8个字节。

(2)strlen与字符数组

strlen计算的是字符串的长度,strlen接收一个地址,然后通过找’\0’来计算字符串长度

以下每个数组都是基于如下字符数组:

char arr[] = { 'a','b','c','d','e','f' };

subject_1:

printf("%d\n", strlen(arr));//输出随机数


strlen接收arr数组首元素地址,也就是从字符’a’开始,向后找’\0’,而该数组中没有’\0’,当找完整个数组后,会越界继续往后找,直到遇到一个’\0’,返回一个随机值。

subject_2:

printf("%d\n", strlen(arr + 0));//输出随机值


arr+0后指向的就是数组首元素地址,strlen接收该地址,向后找\0,会越界往后找,无法确定\0在内存中的位置,输出的就是随机值。

subject_3:

printf("%d\n", strlen(*arr));//非法访问


对arr进行解引用得到字符’a’,而strlen接收的是一个地址,strlen会把字符’a’当作一个地址去访问,字符’a’的ASSIC码值为97,strlen就会访问地址为97的空间,造成非法访问。

subject_4:

printf("%d\n", strlen(arr[1]));//非法访问


arr[1]就是字符’b’,strlen会将字符’b’当作地址进行访问,字符’b’的ASSIC码值为98,直接访问就会造成非法访问的异常。

subject_5:

printf("%d\n", strlen(&arr));//输出随机值


arr进行&操作得到的是整个数组的地址,strlen接收的是整个数组的地址,也是从首元素’a’开始,往后找’\0’,数组内没有’\0’,会继续往后越界找’\0’,返回的是随机值。

subject_6:

printf("%d\n", strlen(&arr + 1));//输出随机值


&arr得到的是整个数组的地址,+1后跳过整个数组,指向的是跳过整个数组后的地址,strlen接收的是跳过整个数组后的地址,从该地址往后找\0,返回一个随机值。

subject_7:

printf("%d\n", strlen(&arr[0] + 1));//返回随机值


arr[0]是数组首元素,对它进行&操作,得到首元素地址,+1跳过一个字节的大小得到第二个元素的地址,strlen接收这个地址,往后找’\0’,会越界直到找到’\0’为止,返回一个随机值。


以下每个数组都是基于如下数组:

char arr[] = "abcdef";

subject_1:

printf("%d\n", strlen(arr));//输出6


arr就是数组首元素地址,strlen接收该地址从字符’a’往后找’\0’,这个字符数组存放的就是字符串,最后有’\0’,‘\0’之前有6个字符,最后输出6。

subject_2:

printf("%d\n", strlen(arr + 0));//返回6


arr是数组首元素地址,arr+0还是数组首元素地址,strlen接收的就是数组首元素地址,计算的是数组内字符串的长度,为6。

subject_3:

printf("%d\n", strlen(*arr));//非法访问


这里对arr进行解引用得到的还是字符’a’,字符’a’的ASSIC码值是97,将97作为地址进行访问会发生异常。

subject_4:

printf("%d\n", strlen(arr[1]));//非法访问


arr[1]就是字符’b’,strlen会将字符’b’当作地址进行访问,字符’b’的ASSIC码值为98,直接访问就会造成非法访问的异常。

subject_5:

printf("%d\n", strlen(&arr));//6


&arr拿到的是整个数组的地址,strlen接收的是数组的地址,计算的还是字符串的长度为6。

subject_6:

printf("%d\n", strlen(&arr + 1));//输出随机值


&arr得到的是整个数组的地址,+1后跳过整个数组,strlen接收到的是跳过整个数组后的地址,从这个地址开始往后找’\0’,直到找到为止,返回的是随机值。

subject_7:

printf("%d\n", strlen(&arr[0] + 1));//输出5


arr[0]取地址得到的是第一个元素的地址,+1就是第二个元素的地址,从第二个字符开始往后找\0,字符串的长度就是5。

3.字符指针

(1)sizeof与字符指针

如下字符指针:

char *p = "abcdef";

subject_1:

printf("%d\n", sizeof(p));//输出4/8


p是指针类型,sizeof( p )计算的就是指针的大小,为4/8个字节。

subject_2:

printf("%d\n", sizeof(p + 1));//输出4


p是cahr*类型的指针,p+1跳过的是一个字节的地址,还是指针类型,大小为4/8个字节。

subject_3:

printf("%d\n", sizeof(*p));//输出1


p指向的是字符串首元素地址,对p解引用得到的是字符串第一个字符,一个字符占1个字节。

subject_4:

printf("%d\n", sizeof(p[0]));//输出1


p是指针,p[0]就相当于*(p+0),得到的还是字符串第一个字符,大小占1个字节。

subject_5:

printf("%d\n", sizeof(&p));//输出4/8


p指向的本身就是一个地址,&p得到的就是地址的地址,计算的还是地址的大小,为4/8个字节。

subject_6:

printf("%d\n", sizeof(&p + 1));//输出4/8


对p进行&操作后,是将&p放到了一个char的二级指针中,而&p+1跳过的是一个char的大小,指向的还是一块地址,地址的大小就是4/8个字节。

subject_7:

printf("%d\n", sizeof(&p[0] + 1));//输出4/8


p[0]表示的是字符串第一个字符,对它&后+1得到的就是第二个字符的地址,大小占4/8个字节。

(2)strlen与字符指针

如下字符指针:

char *p = "abcdef";

subject_1:

printf("%d\n", strlen(p));//输出6


p指向的是字符串的第一个字符的地址,strlen接收这个地址往后找\0,返回这个字符串的长度是6。

subject_2:

printf("%d\n", strlen(p + 1));//输出5


p+1指向的是字符串第二个字符的地址,strlen接收这个地址,从第二个字符开始往后找’\0’,字符串的长度就是5。

subject_3:

printf("%d\n", strlen(*p));//非法访问


对p进行解引用得到第一个字符’a’,strlen会将字符’a’当作一个地址访问,造成非法访问的异常。

subject_4:

printf("%d\n", strlen(p[0]));//非法访问,p[0]就相当于*(p+0)


p[0]就是字符串第一个元素’a’,strlen会将字符’a’当作一个地址访问,造成非法访问的异常。

subject_5:

printf("%d\n", strlen(&p));//随机值


&p是将char*类型的指针p的地址存放在char**的指针中,strlen接收这块地址,往后找\0,返回就是随机值。

subject_6:

printf("%d\n", strlen(&p + 1));//随机值


&p是将char*类型的指针p的地址存放在char**的指针中,在进行+1操作跳过char **的大小,指向的还是一块地址,strlen接收这块地址,往后找\0,返回就是随机值。

subject_7:

printf("%d\n", strlen(&p[0] + 1));//输出5




p[0]是字符串第一个字符‘a’,对它&后得到它的地址,+1得到的就是字符’b’的地址,strlen接收这个地址,往后找\0,返回字符串的长度是5。


到这里,关于指针和数组的深入了解就告一段落啦,蟹蟹大家的支持,欢迎回访!!!

相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
34 3
|
13天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
17天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
17天前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
17天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
21天前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
43 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
38 2
|
1月前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
37 1
|
2月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
2月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。