让你不再惧怕指针——C语言指针及指针进阶详解(上)

简介: 让你不再惧怕指针——C语言指针及指针进阶详解(上)

一、指针初阶


1.指针是什么


我们要从32位或64位机器讲起,对于32位机器来说是由32根总线,这里的位也可以理解为比特位也就是4字节,机器通电后每根地址线会有正负两种电性,正点代表1,负电代表0;所以总共有2^32种可能,也就是2^32个地址,一个小单元为一个字节,一个字节给对应的的地址;


这里我们就明白:

1. 在32位的机器上,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。

2. 那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地

址。


我们也可以这样理解:


1. 内存和内存地址:在计算机中,内存是用于存储数据的地方。每个内存单元都有一个唯一的地址,用于标识和访问它。我们可以将内存地址视为存储数据的房间号,而内存单元则是房间中存放的数据。


2. 指针的定义和作用:指针是一种特殊的变量,它存储了一个内存地址。可以将指针视为存放房间号的盒子,它并不存放数据本身,而是指向存放数据的内存位置。指针的作用是提供了直接访问和操作内存中数据的能力。


我们可以将指针比喻为计算机中的房间号,它允许我们直接访问和操作内存中的数据。


总结:

1. 指针变量是用来存放地址的,地址是唯一标示一个内存单元的。
2. 指针的大小在32位平台是4个字节,在64位平台是8个字节。


指针是什么?

指针理解的2个要点:
1. 指针是内存中一个最小单元的编号,也就是地址
2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

总结:指针就是地址,口语中说的指针通常是指指针变量


2.指针和指针类型


2.1指针


我们可以用&操作符取出一个变量的地址,存储在一个int * 类型的变量中

int main()
{
  int a = 10;
  //在创建a变量的同时在内存中开辟一个int大小的空间存储a变量
  int* pa = &a;
  //使用&操作符取出a的地址
  //int* 表明pa是一个指针 存储着a变量的地址 也代表着pa指向a变量
  return 0;
}


2.2指针的类型


我们知道在C语言中有着不同的变量类型,例如:整形,浮点型等。那指针有没有类型呢?

准确的说:有的(这里的NULL表示将指针置空,没有指向任何空间)

int *pa=NULL;//表明指针pa是存放int类型变量的地址
char *pc=NULL;//表明指针pc是存放char类型变量的地址
short *ps=NULL;//表明指针ps是存放short类型变量的地址
long *pl=NULL;//表明指针pl是存放long类型变量的地址
float *pf=NULL;//表明指针pf是存放float类型变量的地址
double *pb=NULL;//表明指针pb是存放double类型变量的地址


这就是指针的类型,定义方式:type+*,*表明定义一个指针,type是这个指针的类型


2.3指针加减整数


int main()
{
  int n = 10;
  char* pc = (char*)&n;
  int* pa = &n;
  printf("%p\n", &n);
  printf("%p\n", pc);
  printf("%p\n", pc + 1);
  printf("%p\n", pa);
  printf("%p\n", pa + 1);
  return 0;
}


9e5ea5ddbd8f4edf91afc8d4dfd2eced.png

总结:这就是指针类型的意义决定指针向前或者向后走一步有多大(距离)


2.4指针的解引用


int main()
{
  int n = 0x11223344;
  char* pc = (char*)&n;
  int* pa = &n;
  *pc = 0;
  *pa = 0;
  return 0;
}


294bc4f5ee944fa698d1353bca6ca679.png

890f0e32444a4350aa94f3ae71770bc2.png

总结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。

比如:按照上面的例子char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。


3.野指针


概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)


3.1野指针的成因


1. 指针未初始化

#include <stdio.h>
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
  *p = 20;
return 0;
}


2. 指针越界访问

int main()
{
  int arr[10] = {0};
  int *p = arr;
  int i = 0;
  for(i=0; i<=11; i++)
 {
    //当指针指向的范围超出数组arr的范围时,p就是野指针
    *(p++) = i;
 }
  return 0;
}


3.2 如何在写代码的过程中规避野指针


1. 指针初始化

2. 小心指针越界

3. 指针指向空间释放,及时置NULL

4. 避免返回局部变量的地址

5. 指针使用之前检查有效性


4.指针运算


指针-指针

int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int* left = arr;
  while (*left != 10)
  {
    left++;
  }
  printf("%d\n",left-arr);
  return 0;
}


878bf636fd904fc6950888491b6b5222.png


a286451b1f204f4c96796a1b1a77a17f.png

总结:指针和指针相减得到的是两个指针相距之间元素的个数


5.指针和数组


int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
  printf("%p\n", arr);
  printf("%p\n", &arr[0]);
  return 0;
}


d0fc2a50a7df48ba95752ad04e9df9b1.png

我们不难发现打印数组的地址和数组首元素的地址是一样的;

结论:数组名表示的是数组首元素的地址

那我们就可以用指针来访问数组

int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
  int* p = arr;
  int sz = sizeof(arr) / sizeof(arr[0]);
  int i = 0;
  for (i = 0; i < 10; i++)
  {
    printf("%d ", *(p + i));
  }
  return 0;
}


4167b83f2a5645b19bb8e14ea2d740b7.png


6.二级指针


指针变量也是变量,是变量就有地址,存放指针变量的地址就是二级指针;

int main()
{
  int a = 10;
  int* p = &a;//p是一个一级指针指向a
  int** ppa = &p;
  //int * 表明*ppa是一个指针指向p,而p也是一个指针因此ppa存放着一个指针的地址是一个二级指针
  printf("%d\n", a);
  **ppa = 30;//*(*ppa)得到p的地址即*(p)在对其解引用等价于a=30
  printf("%d\n", a);
  return 0;
}


ab18cbc6a2e94db1984a8394b9b54dd8.png

相关文章
|
1月前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
94 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
1月前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
61 9
|
1月前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
46 7
|
2月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
182 13
|
2月前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
2月前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
147 3
|
2月前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
2月前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
45 1
|
2月前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
2月前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。