【学习笔记之我要C】深入理解数组与指针

简介: 【学习笔记之我要C】深入理解数组与指针

一、前置提醒

sizeof()是一个单目操作符,用来计算数据长度,以字节为单位

 strlen是C语言标准库定义的一个函数,用来计算字符串的长度,直到空结束字符,但不包括空结束字符。查看源码我们可以知道,strlen要接收一个指针,也就是接收一个地址。

 数组名是数组首元素的地址,但是有2个例外:1.sizeof(数组名),这里数组名表示整个数组;2. &数组名,这里数组名表示整个数组,取出的是整个数组的地址。

二、一维数组

  先计算打印结果,然后在看后面的答案,笔试!!!不要直接复制到编译器上。

  1. 整形数组
int 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));
  printf("%d\n", sizeof(&a + 1));
  printf("%d\n", sizeof(&a[0]));
  printf("%d\n", sizeof(&a[0] + 1));
  return 0;
}
int main() {
  //以下都是32位机情况下的计算结果
  int a[] = { 1,2,3,4 };
  printf("%d\n", sizeof(a));
  //一个int类型占4个字节,4个int类型,打印结果为16
  printf("%d\n", sizeof(a + 0));
  //a作为数组名不是单独出现的,所以这里a表示首元素地址
  //首元素地址+0之后,还是首元素地址
  //一个地址的大小为4
  printf("%d\n", sizeof(*a));
  //a表示首元素地址,*a就是对首元素地址解引用,得到整型1
  //一个整型大小为4个字节
  printf("%d\n", sizeof(a + 1));
  //a + 1得到的是第二个元素的地址
  //一个地址的大小为4
  printf("%d\n", sizeof(a[1]));
  //a[1]取到的是第二个元素
  //int类型大小为4个字节
  printf("%d\n", sizeof(&a));
  //取到整个数组的地址,数组的地址也是地址
  //一个地址的大小为4
  printf("%d\n", sizeof(*&a));
  //&a取到的是整个元素的地址,解引用后得到整个数组
  //4个int类型,打印结果为16
  printf("%d\n", sizeof(&a + 1));
  //&a取到一个地址,地址+1后得到的还是一个地址
  //一个地址的大小为4
  printf("%d\n", sizeof(&a[0]));
  //操作符[]的优先级比&高
  //先a[0],表示数组的第一个元素
  //然后取地址&,取到第一个元素的地址
  printf("%d\n", sizeof(&a[0] + 1));
  //在取到第一个元素的地址上+1,得到第二个元素的地址
  return 0;
}
  1. 字符数组
int 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));
  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;
}
int main() {
  //以下都是32位机情况下的计算结果
  char arr[] = { 'a','b','c','d','e','f' };
  printf("%d\n", sizeof(arr));
  //一个char类型大小为1字节,6个char类型,打印6
  printf("%d\n", sizeof(arr + 0));
  //arr作为数组名不是单独出现的,所以这里arr表示首元素地址
  //首元素地址+0之后,还是首元素地址
  //一个地址的大小为4字节
  printf("%d\n", sizeof(*arr));
  //arr表示首元素地址,解引用后得到首元素
  //一个char类型大小为1字节
  printf("%d\n", sizeof(arr[1]));
  //表示第二个元素,一个char类型大小为1字节
  printf("%d\n", sizeof(&arr));
  //取的整个数组的地址,一个地址的大小为4字节
  printf("%d\n", sizeof(&arr + 1));
  //取到整个数组的地址,然后地址+1,得到另一个地址
  printf("%d\n", sizeof(&arr[0] + 1));
  //取到首元素的地址后+1,得到第二个元素的地址
  //注意:这里是strlen,不是sizeof了,不要继续用sizeof算(doge)
  printf("%d\n", strlen(arr));
  //strlen找到‘\0’才停下来,
  //但是arr并没有存储‘\0’
  //那么strlen会一直找下去,直到找到一个‘\0’为止
  //所以打印出来是一个随机值
  printf("%d\n", strlen(arr + 0));
  //arr+0得到首元素,
  //然后从首元素开始计算,结果发现怎么还是没有‘\0’
  //于是编译器又默默打印一个随机值
  printf("%d\n", strlen(*arr));
  //*arr解引用得到字符‘a’,
  //问题出现了,strlen只会接收地址
  //所以这行代码是错的
  printf("%d\n", strlen(arr[1]));
  //arr[1]得到字符‘b’,报错
  printf("%d\n", strlen(&arr));
  //&arr取到整个数组的地址,
  //BUT这个数组没有‘\0’,
  //于是编译器双默默打印一个随机值
  printf("%d\n", strlen(&arr + 1));
  //&arr + 1取到一个地址
  //BUT鬼知道‘\0’会在哪儿出现啊
  //于是编译器叒默默打印一个随机值
  printf("%d\n", strlen(&arr[0] + 1));
  //取到首元素地址之后+1,得到第二个元素
  //BUT第二元素也不知道‘\0’会在哪儿出现啊
  //于是编译器叕默默打印一个随机值
  return 0;
}
int 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));
  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;
}
int main() {
  //以下都是32位机情况下的计算结果
  char arr[] = "abcdef";
  printf("%d\n", sizeof(arr));
  //字符串在存储的时候会在最后加上‘\0’
  //sizeof不是strlen,它会计算‘\0’
  //所以7个char类型,打印7
  printf("%d\n", sizeof(arr + 0));
  //arr作为数组名不是单独出现的,所以这里arr表示首元素地址
  //首元素地址+0之后,还是首元素地址
  //一个地址的大小为4字节
  printf("%d\n", sizeof(*arr));
  //这里arr表示首元素地址,解引用后得首元素,一个char类型大小为1
  printf("%d\n", sizeof(arr[1]));//表示第二个元素,一个char类型大小为1
  printf("%d\n", sizeof(&arr));//整个数组的地址,一个地址大小为4
  printf("%d\n", sizeof(&arr + 1));//地址+1得到的还是地址,一个地址大小为4
  printf("%d\n", sizeof(&arr[0] + 1));//得第二个元素的地址,一个地址大小为4
  printf("%d\n", strlen(arr));
  //字符串在存储的时候会在最后加上‘\0’
  //strlen遇到‘\0’就停止,且不计算‘\0’
  //所以打印6
  printf("%d\n", strlen(arr + 0));
  //得到第一个字符的地址,开始计算长度,遇到‘\0’就停止,打印6
  printf("%d\n", strlen(*arr));//strlen要接收地址,报错
  printf("%d\n", strlen(arr[1]));//strlen要接收地址,报错
  printf("%d\n", strlen(&arr));//取整个数组的地址,打印6
  printf("%d\n", strlen(&arr + 1));
  //取整个数组的地址,+1跳过这个数组
  //这样就不知道哪里有‘\0’了
  //打印一个随机值
  printf("%d\n", strlen(&arr[0] + 1));//取到‘b’的地址,开始计算,结果为5
  return 0;
}

三、二维数组

int 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;
}
int main() {
  //二维数组
  int a[3][4] = { 0 };
  printf("%d\n", sizeof(a));
  //二维数组三行四列,都是int类型
  //3 * 4 * 4得48
  printf("%d\n", sizeof(a[0][0]));//第一行第一个元素,打印4
  printf("%d\n", sizeof(a[0]));
  //a[0]作为数组名单独放在sizeof内部,表示第一行
  //一行存放了4个int类型元素,得16
  printf("%d\n", sizeof(a[0] + 1));
  //a[0]没有单独放在sizeof内部,也没有取地址,表示第一行第一元素的地址,
  //+1得到第一行第二个元素的地址,一个地址大小为4
  printf("%d\n", sizeof(*(a[0] + 1)));//解引用得到第一行第二个元素,一个int类型大小为4
  printf("%d\n", sizeof(a + 1));
  //表示首元素地址,代表第一行
  //+1得第二行地址,一个地址大小为4
  printf("%d\n", sizeof(*(a + 1)));//解引用得到第二行数组,4个int类型大小为16
  printf("%d\n", sizeof(&a[0] + 1));//&a[0]取得第一行地址,&a[0] + 1得第二行地址,4
  printf("%d\n", sizeof(*(&a[0] + 1)));//对第二行地解引用,得第二行数组,4个int类型大小为16
  printf("%d\n", sizeof(*a));//a表示首元素地址,解引用得第一行数组,4个int类型大小为16
  printf("%d\n", sizeof(a[3]));
  //如果存在的话,a[3]表示第四行的数组名,
  //sizeof不需要它存在,推算出类型进行计算,4个int类型大小为16
  return 0;
}

四、指针

int 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));
  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;
}
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));
  //指针P存放的是首元素‘a’的地址
  //解引用得到元素‘a’
  //一个char类型的大小为1
  printf("%d\n", sizeof(p[0]));//p[0]相当于是对p进行解引用,得到元素‘a’,大小为1
  printf("%d\n", sizeof(&p));
  //指针也是一个变量,他也会开辟一个地址来存储
  //取p的地址得到的还是一个地址,大小为4
  printf("%d\n", sizeof(&p + 1));//地址+1得到的还是一个地址,大小为4
  printf("%d\n", sizeof(&p[0] + 1));
  //得到‘a’的地址后
  //再对‘a’取地址得到的还是一个地址
  //一个地址大小为4
  printf("%d\n", strlen(p));//p存放的是‘a’的地址,从‘a’开始计算,结果为6
  printf("%d\n", strlen(p + 1));//p+1后得到‘b’的地址,从‘b’开始计算,结果为5
  printf("%d\n", strlen(*p));//p解引用后得到‘a’,strlen要接收一个地址,报错
  printf("%d\n", strlen(p[0]));//p[0]相当于是对p进行解引用,得到元素‘a’,报错
  printf("%d\n", strlen(&p));
  //取到指针p的地址,从p的地址开始计算
  //但是不知道哪里会有‘\0’,所以打印出一个随机值
  printf("%d\n", strlen(&p + 1));//随机值
  printf("%d\n", strlen(&p[0] + 1));
  //p[0]相当于是对p进行解引用,得到元素‘a’
  //再对‘a’取地址,得到‘a’的地址,+1得到‘b’的地址
  //从‘b’开始计算,结果为5
  return 0;
}

就这?就这?就这?不就是两把头发的事情吗?

目录
相关文章
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
224 3
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
457 4
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
215 2
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
2097 13
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
952 4
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
286 0