C语言指针初阶详解


前言

指针是C语言的一个非常重要的概念,也是C语言的一个重要特色。正确而灵活地运用它,可以有效地表示复杂的数据结构。直接通过内存地址对数据进行处理,可以使程序简洁、紧凑、高效。


一、指针的基本概念:

在计算机中,所有的数据都是存放在存储器中的,每个存储单元的大小为1字节,为了便于管理,必须为每个存储单元编号,该编号就是存储单元的“地址”,每个存储单元拥有一个唯一的地址。

理解指针的两个要点:

  1. 指针是内存中最小存储单元的编号,也就是内存地址。
  2. 平时我们口语中说的指针,通常指的是指针变量(用来存放内存地址对变量)。

在这里插入图片描述
我们可以通过&(取地址操作符) 取出变量的地址,把地址可以存放到一个指针变量中

#include <stdio.h>
int main()
{
    
    
	int a = 10;//在内存中开辟一处空间
	printf("%d", a);//运行结果为10
	int* p = &a;//这里取出变量a的地址,放到指针变量p中
	*p = 20;//通过对p解引用找到a来修改a的值
	printf("%d", a);//运行结果为20
	return 0;
}

我们通过一个例子来强化一下对指针的理解:
在这里插入图片描述
好比a入住了酒店,如果你想找到a,一个房间一个房间的找的话,效率大大降低。最好的办法就是通过房间号去找,精准高效。这里的住户相当于变量a,房间号就是a的内存地址,通过对该地址的解引用就可以找到a。

那指针变量占几个字节呢?

  • 在32位机器上,地址是32个0或1组成的二进制序列,那地址就得用4个字节的空间来存储,所以一个指针变量的大小就应该是4个字节。
  • 同理如果在64位机器上,一个指针变量的大小就应该是8个字节,才能存放一个地址。

注意:指针变量大小和存储数据的类型无关,在同一环境下,指针变量大小一样。

二、指针的类型:

我们都知道,变量有不同的类型,整形、浮点型等。那指针有没有类型呢?

int main()
{
    
    
	int* p1 = NULL;//NULL是空指针
	char* p2 = NULL;
	float* p3 = NULL;
	return 0;
}

看上面的代码我们就知道:指针的定义方式是type+*。

例如:

  • int类型的指针是为了存放int*类型的变量的地址
  • char类型的指针是为了存放char*类型的变量的地址
  • float类型的指针是为了存放float*类型的变量的地址

那这种定义方式有什么意义呢?

1.指针±整数:

#include <stdio.h>
int main()
{
    
    
	char a = 'a';
	char* pa = &a;
	int b = 10;
	int* pb = &b;
	printf("%p\n", pa);//0x00D5FEBB
	printf("%p\n", pa + 1);//0x00D5FEBC
	printf("%p\n", pb);//0x00D5FED0
	printf("%p\n", pb + 1);//0x00D5FED4
	return 0;
}

看上面代码运行结果:

  • char*类型的变量+1地址增加1个字节
  • int*类型的变量+1地址增加4个字节

总结: 指针的类型决定了指针向前和向后走一步有多大(距离)。

2.指针的解引用:

#include <stdio.h>
int main()
{
    
    
	int n = 0x11223344;
	char* p1 = (char*)&n;//将n地址强制转化为char*类型
	int* p2 = &n;
	*p1 = 0;//n变为0x11223300
	*p2 = 0;//n变为0x00000000
	return 0;
}

总结:

  • 指针变量的类型决定了对它解引用的时候有多大的权限(能操作几个字节)。
  • 比如:char的指针解引用只能访问一个字节,而int可以访问四个字节。

三、指针运算:

1.指针±整数:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p = &arr[0];
	printf("%d\n", *p);//结果为1
	printf("%d\n", *(p + 1));//结果为2
	return 0;
}

2.指针-指针:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	printf("%d", p2 - p1);
	//运行结果为1,说明p2和p1之间有1个变量
	return 0;
}

在这里插入图片描述

3.指针的关系运算:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	if (p2 > p1)//指针的比较
	{
    
    
		printf("yes");//运行结果为yes
	}
	return 0;
}

标准规定:

允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

四、指针和数组:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	printf("%p", arr);//00F3CC00
	printf("%p", &arr[0]);//00F3CC00
	//可以看到数组名和数组首元素地址是一样的
	return 0;
}

结论:数组名表示的是数组首元素的地址。(两种情况除外)

两种情况:

  1. 数组名在sizeof内部,如sizeof(arr),数组名代表的是整个数组。
  2. &arr,这个时候,数组名也代表的是整个数组。

五、二级指针:

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

#include <stdio.h>
int main()
{
    
    
	int a = 10;
	int* pa = &a;//pa存放a的地址
	int** ppa = &pa;//ppa存放pa的地址
	**ppa = 20;//把a的值改成了20
	int b = 30;
	*ppa = &b;//相当于pa中存了b的地址
	return 0;
}

六、指针数组:

指针数组是数组还是指针??
答案是:数组。是存放指针变量的数组
我们知道整形数组存放整形的,字符数组存放字符。
那指针数组自然就是存放指针变量的。
在这里插入图片描述


结尾

指针是一把双刃剑,用得好编写程序更加高效,用的不好会出现很多程序错误,所以每一个学C语言的人学好指针至关重要!
以上就是初阶指针的内容,希望对于刚读完此博客的你有所帮助。

猜你喜欢

转载自blog.csdn.net/weixin_61661271/article/details/124558398