Bootstrap

零基础学指针(上)

系列文章目录

🎈 🎈 我的CSDN主页:OTWOL的主页,欢迎!!!👋🏼👋🏼
🎉🎉我的C语言初阶合集C语言初阶合集,希望能帮到你!!!😍
😍 👋🏼🎉🎊创作不易,欢迎大家留言、点赞加收藏!!! 🥳😁😍



前言

这篇博客是指针系列 的第一篇
将从内存中变量的存储和指针变量的语法和定义,指针的俩个运算符,分别是取值运算符(*)和取地址运算符(&),
然后还会介绍指针变量的运算。


一、内存中变量的存储

在内存中,每个变量都有一个唯一的地址。
当你声明一个变量时,比如int a = 5;,编译器会在内存中为a分配一个空间,并存储值5
同时,a 也有一个内存地址,这个地址可以通过 指针 来访问。

这里的指针是 指针变量 的简称。

  • 例如:

代码如下(示例):

#include<stdio.h>

int main()
{
	//定义一个整型变量 a
	int a = 5;
	//输出变量 a的地址
	printf("&a = %p\n", &a);

	return 0;
}
  • 结果如图:

  • 内存的分布图(示例)

解释:变量a是整型,在内存中占4个字节(连续的,输出 &a 只会输出首地址);
内存 在分配时是 随机的。(即每次运行时,产生的地址结果是不同的)

注:0X代表的是十六进制数

二、指针变量的定义和语法

(1)指针变量的定义

指针变量是一种特殊的变量,它存储的不是数据本身,而是数据在内存中的地址。
你可以把指针变量想象成一个“箭头”,它指向了内存中存储数据的那个位置。

(2)指针变量的语法

  • 在C语言中,定义指针变量的语法如下:
数据类型 *指针变量名;

1. 数据类型:指针所指向的数据的类型。

比如,如果你有一个指向整数的指针,那么数据类型就是int

2. *:星号表示这是一个指针变量。

3. 指针变量名:你给这个指针变量起的名字,比如pptr等。

  • 例如:

代码如下(示例):

#include <stdio.h>

int main() {
    int a = 10; // 定义一个整数变量 a,并赋值为 10
    int* p; // 定义一个指向整数的指针变量 p

    p = &a; // 将变量a的地址赋给指针变量 p

    printf("a的值是: %d\n", a); // 输出 a的值
    printf("a的地址是: %p\n", &a); // 输出 a的地址
    printf("指针p的值(即a的地址)是: %p\n", p); // 输出指针 p的值,也就是a的地址
    printf("通过指针p访问a的值是: %d\n", *p); // 通过指针 p访问a的值

    return 0;
}
  • 结果如图:

三、指针的运算符

(1)取地址运算符(&)

取地址运算符& 用于获取变量的内存地址。

  • 例如:

代码如下(示例):

#include<stdio.h>

int main()
{
	//定义一个整型变量 a
	int a = 10;
	int* p; // 声明一个指向 int 的指针变量 p
	p = &a; // 将变量 a 的地址赋给指针 p
	//输出变量 a 的地址
	printf("&a = %p\n", &a);
	printf("p = %p\n", p);

	return 0;
}

  • 结果如图:

  • 内存的分布图(示例)

在这里插入图片描述

(2)取值运算符(*)

取值运算符*用于通过指针访问它所指向的内存地址中的值。

  • 例如:

代码如下(示例):

#include<stdio.h>

int main()
{
	//定义一个整型变量 a
	int a = 10;
	int* p = &a; // 声明一个指向 int 的指针变量 p,p 指向 a 的地址
	int b = *p; // 通过指针 p 获取 a 的值,并赋给 b

	//输出变量a的值
	printf("a = %d\n", a);
	//输出变量b的值
	printf("b = %d\n", b);

	return 0;
}
  • 结果如图:

四、指针变量的运算

因为指针是一个变量,但它存储的不是普通的数据值,而是另一个变量的内存地址
指针的运算其实就是内存单元(地址)之间的运算
指针的运算主要包括 指针的 加减运算 和 指针的 比较运算

(1)指针的加减运算

(1.1)指针变量加减整数

指针的加减整数运算 实际上是对指针所指向的内存地址进行加减。
由于指针指向的是某种类型的数据,所以加减运算的 步长是这种类型数据的大小。

  • 例如:

代码如下(示例):

#include <stdio.h>

int main() {
	//定义一个整型的一维数组,大小是 5,里面存放着 1,2,3,4,5
	int a[5] = { 1, 2, 3, 4, 5 };
	int* p = &a[0]; // p指向数组 a的第一个元素

    // 指针与整数相加:跳过数组中的元素
    p = p + 2; // p现在指向arr[2],因为从arr[0]开始加了2个整型类型的大小
    printf("*p = %d\n", *p); // 输出3

    // 指针与整数相减:回到之前的元素
    p = p - 2; // p现在指向arr[0],因为从arr[2]开始减了2个整型类型的大小
    printf("*p = %d\n", *p); // 输出1

    return 0;
}

  • 结果如图:

(1.2)指针变量 减 指针变量

当你执行两个指针变量的减法运算时,你实际上是在计算它们所指向的内存地址之间的差值,
但这个差值并不是以字节为单位,而是以指针所指向的数据类型的大小为单位
实际上就是 两个指针之间相隔的元素个数

注意:两个指针变量的减法运算只能在指向同一数组或连续内存块的指针之间进行。
如果两个指针不指向同一数组或连续内存块,
那么减法运算的结果是未定义的, 可能会导致程序崩溃或产生不可预测的行为。

#include <stdio.h>

int main() {
    int arr[5] = { 10, 20, 30, 40, 50 }; // 定义一个整数数组
    int* p1 = &arr[1]; // 定义一个指向 arr[1]的指针
    int* p2 = &arr[4]; // 定义一个指向 arr[4]的指针

    // 计算两个指针之间的差值
    int dif = p2 - p1; // 这将计算 p2 和 p1 之间相隔的元素个数

    // 输出结果
    printf("dif: %d\n", dif);
    // 输出: dif is: 3

    // 验证通过指针算术访问数组元素
    printf("p1: %d\n", *p1); // 输出:p1: 20
    printf("p1 + dif: %d\n", *(p1 + dif)); // 输出: p1 + dif: 50,这里 p1 + dif 实际上等于 p2

    return 0;
}
  • 结果如图:

(2)指针的比较运算

指针的比较运算通常用于比较两个指针是否指向 同一个内存地址 或比较 它们在内存中的相对位置。

  • 例如:

代码如下(示例):

#include<stdio.h>

int main()
{
	//定义一个整型变量 a,初始化为 10
	int a = 10;
	//定义一个整型变量 b,初始化为 20
	int b = 20;
	// 声明一个指向 int 的指针变量 p1,p1 指向 a 的地址
	int* p1 = &a;	
	// 声明一个指向 int 的指针变量 p2,p2 指向 b 的地址
	int* p2 = &b;
	//判断
	if (p1 == p2) 
	{
		// 这两个指针指向不同的地址,所以不会执行这里的代码
	}
	else 
	{
		// 这两个指针指向不同的地址,所以执行这里的代码
		printf("hehe\n");
	}

	return 0;
}
  • 结果如图:

总结

1. 指针是一个变量,用于存储另一个变量的内存地址。

2. 取地址运算符 & 用于获取变量的内存地址。

3. 取值运算符 * 用于通过指针访问它所指向的内存地址中的值。

4. 指针的运算包括加减运算和比较运算,用于操作 指针所指向的内存地址。

5. 指针类型的意义
(1)指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如:char*的指针解引用就只能访问一个字节,
int* 的指针解引用能访问四个字节
(2)指针的类型决定了指针向前或者向后走一步有多大(距离)。


每天都在学习的路上!
On The Way Of Learning

;