C语言· 指针· 上篇(初阶内容· 超详细系列· 一篇拿下指针基础!)

前言:Hello大家好😘,我是心跳sy,今天为大家带来C语言指针的知识点,由于内容过多,跨度较大,指针的篇章分为初阶和进阶两个章节,本篇文章对指针的基础初阶知识点进行汇总,内容全面,刚接触C的友友们也可放心食用哦💞💞💞我们一起来看看吧! 

目录

一、指针和指针变量 💫

1、⭐️什么是指针?⭐️

2、⭐️什么是指针变量?⭐️

二、指针类型 💫

1、⭐️指针类型都有什么?⭐️

2、⭐️指针类型的意义⭐️

三、野指针 💫

1、⭐️野指针的成因⭐️

2、⭐️如何规避野指针⭐️

四、指针运算 💫

1、⭐️指针 ✚ ━ 整数⭐️

2、⭐️指针 ━ 指针 ⭐️

3、⭐️指针的关系运算⭐️

五、指针和数组 💫

1、⭐️指针和数组的联系⭐️

2、⭐️使用指针可遍历数组⭐️

3、⭐️指针与数组的综合运用⭐️

六、二级指针 💫

1、⭐️二级指针的概念⭐️

2、⭐️二级指针的解引用⭐️

3、⭐️二级指针与一级指针联合运用实例⭐️

七、指针数组 💫


🎀小 tip:本文内容较长,基础知识全面,所有代码皆配有详细解释,友友们放心观看💯

一、指针和指针变量 💫

1、⭐️什么是指针?⭐️

⭕️指针是内存中一个最小单元的编号,也就是地址;地址唯一标识一块地址空间。

⭕️平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量,指针对于程序员来说是一个重要的工具,可以有效地管理和操作内存中的数据。

2、⭐️什么是指针变量?⭐️

⭕️指针变量是存储内存地址的变量,指针变量的定义格式为 "数据类型 * 指针变量名;",其中“数据类型”是指针所指向的数据的类型,“指针变量名”是指针变量的名称;

👉如:"int *p" 表示定义了一个指针变量p,它存储的是一个地址,该地址指向一个int类型的变量。指针变量的值是通过使用取地址运算符“&”赋予的,例如 "p = &a" 表示把变量a的地址赋值给指针变量p。

⭕️指针的大小在32位平台上是4个字节,在64位平台是8个字节

二、指针类型 💫

1、⭐️指针类型都有什么?⭐️

//char*类型指针,为了存放char类型变量的地址
char *p1=NULL;
//int*类型指针,为了存放int类型变量的地址
int *p2=NULL;
//short*类型指针,为了存放short类型变量的地址
short *p3=NULL;
//float*类型指针,为了存放float类型变量的地址
float *p4=NULL;
//double*类型指针,为了存放double类型变量的地址
double *p5=NULL; 

2、⭐️指针类型的意义⭐️

🌈① 不同的指针类型决定了指针向前向后走一步有多大的距离

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	int n = 10;
	char *p1 = (char* )&n;
	int* p2 = &n;

	printf("%p\n", &n);
	printf("%p\n", p1);
	printf("%p\n", p1+1);
	printf("%p\n", p2);
	printf("%p\n", p2+1);

	return 0;
}

 

🍀解释:

👉代码定义了一个整型变量 n 并初始化为 10定义了一个字符型指针 p1,并将n 的地址强制转换为 char* 类型后赋值给 p1定义了一个整型指针 p2,并将 n 的地址赋值给p2,并分别打印、n,p1, p1+1( n 的地址加上一个字节),p2, p2+1( n 的地址加上 sizeof(int) 个字节)的地址值

👉char* 类型的指针每次增加一个单位会向后移动一个字节 

👉在 32 位系统上,int 类型通常占用 4 个字节,所以p2+1 将指向 n 的地址加上 4 个字节。 

💯总结:

 

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

👉比如:char* 的指针解引用就只能访问1个字节,而 int*的指针解引用就能访问4个字节

三、野指针 💫

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

1、⭐️野指针的成因⭐️

🌈① 指针创建时未初始化

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

🌈② 指针越界访问

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

🌈③ 指针指向被释放的内存 

int main() {
    int *p = (int*)malloc(sizeof(int)); // 动态分配内存
    *p = 10; // 在分配的内存中存储数据
    printf("Value: %d\n", *p); // 输出:Value: 10
    free(p); // 释放内存
    // 错误示例:p 现在是野指针,但它被继续使用
    printf("Value after free: %d\n", *p); // 未定义行为,可能会输出10,也可能会崩溃
    return 0;
}

2、⭐️如何规避野指针⭐️

🌈① 指针初始化

int *p = NULL;  // 初始化指针为NULL,表示它不指向任何有效的内存地址

🌈② 小心指针越界

int arr[10];
for(int i = 0; i < 10; i++) {
    // 安全地访问数组元素
    arr[i] = i;
}

🌈③ 指针指向空间释放即使置NULL

int *ptr = (int*)malloc(sizeof(int) * 10);  // 分配内存
free(ptr);                                   // 释放内存
ptr = NULL;                                  // 将指针置为NULL,避免悬挂指针

🌈④ 避免返回局部变量的地址

void foo() {
    int local_var = 42;  // 局部变量
    // 错误示例:返回局部变量的地址
    // int *p = &local_var; 
    // return p;
    
    // 正确做法:使用动态内存分配或者将变量定义为静态生命周期
    static int static_var = 42;
    int *p = &static_var;
}

🌈⑤ 指针使用之前检查有效性

int *p = NULL;
if (p != NULL) {
    // 如果p不为NULL,则安全地使用指针
    *p = 42;
}

四、指针运算 💫

1、⭐️指针 ✚ ━ 整数⭐️

⭕️指针加上或减去一个整数,指针会移动若干个它所指向类型大小的单位。

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p = &arr[2]; //p指向arr[2],即30
    
    printf("Value of *(p + 1): %d\n", *(p + 1)); // 移动到arr[3]的位置,输出40
    // p+1将p向后移动了一个int类型的大小(通常是4字节),即移动到了arr[3]
    
    printf("Value of *(p - 1): %d\n", *(p - 1)); // 移动到arr[1]的位置,输出20
    // p-1将p向前移动了一个int类型的大小,即移动到了arr[1]
    
    return 0;
}

2、⭐️指针 ━ 指针 ⭐️

⭕️两个指针相减得到它们之间元素的数量(如果它们指向同一个数组的话)

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p1 = &arr[0];
    int *p2 = &arr[3];
    
    int difference = p2 - p1; // 计算p2和p1之间的位置差
    
    printf("相差%d个元素\n", difference); // 输出3,因为p2和p1之间相差3个元素
    
    return 0;
}

3、⭐️指针的关系运算⭐️

⭕️指针的关系运算是比较两个指针指向的地址

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p1 = &arr[0];
    int *p2 = &arr[3];
    
    if(p1 < p2) {
        printf("p1 is less than p2\n"); // 因为p1指向arr[0], p2指向arr[3], 所以p1 < p2
    }
    
    return 0;
}

五、指针和数组 💫

1、⭐️指针和数组的联系⭐️

👉在C语言中,指针和数组是紧密相关的概念,数组名本身就是指向数组第一个元素的指针 

#include <stdio.h>
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;
}

 

🔴地址相同,可见数组名和数组首元素地址是一样的

🎀结论:

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

🔶1. 当数组名作为 `sizeof` 操作符的操作数时

int arr[10];
   size_t size = sizeof(arr); // sizeof(arr) 返回整个数组的大小,而不是首元素的地址

在这种情况下,sizeof 操作符返回的是整个数组占用的总字节数,而不是首元素的地址。因为sizeof 需要知道整个数组的大小,而不是单纯的首个元素的地址 ;

🔶2. 当数组名作为 `&`(取地址)操作符的操作数时

int arr[10];
   int (*ptr)[10] = &arr; // &arr 返回整个数组的地址,类型是 int(*)[10]

👉在这里,&arr 返回的是整个数组的地址,而不是首元素的地址;

👉这里的类型是int (*)[10],表示一个指向包含10个 int 类型元素的数组的指针。  

2、⭐️使用指针可遍历数组⭐️

#include <stdio.h>

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int *p = arr; // 指向数组的第一个元素
    
    for(int i = 0; i < 5; i++) {
        printf("Value: %d\n", *(p + i)); // 使用指针遍历数组
    }
    
    return 0;
}

3、⭐️指针与数组的综合运用⭐️

#include <stdio.h>

void printArray(int *arr, int size) {
    for(int i = 0; i < size; i++) {
        printf("Value: %d\n", *(arr + i)); // 使用指针访问数组元素
    }
}

int main() {
    int arr[] = {10, 20, 30, 40, 50};
    int size = sizeof(arr) / sizeof(arr[0]); // 计算数组大小
    
    printArray(arr, size); // 传递数组名和数组大小(即第一个元素的地址)
    
    return 0;
}

六、二级指针 💫

❓思考:指针变量也是一种变量,是变量那么就有对应的地址,那指针变量的地址存放在哪里呢?

👉答:存放在二级指针变量里 

1、⭐️二级指针的概念⭐️

🔴二级指针(或指向指针的指针)是指一个指针变量存储的是另一个指针变量的地址,而后者又可以指向某个数据。

👉举个例子:

2、⭐️二级指针的解引用⭐️

⭕️*ppa通过对ppa中的地址进行解引用,这样找到的是pa,也就是说*ppa其实访问的就是pa

int b = 20;
*ppa = &b;//等价于 pa = &b;

⭕️**ppa先通过*ppa找到pa,然后对pa进行解引用操作,找到a,两次解引用 

**ppa = 30;
//等价于*pa = 30;
//等价于a = 30;

3、⭐️二级指针与一级指针联合运用实例⭐️

void updateValue(int **pp) 
{
    // 使用二级指针修改一级指针所指向的整数值
    **pp = 200; // 直接更改p所指向的值
}

int main()
{
    int *p = NULL; // 定义一个一级指针
    int value = 10; 
    p = &value; // 一级指针p指向整型变量value的地址

    printf("Before updateValue: %d\n", *p); // 输出指针p所指向的当前值:10

    // 传递一级指针的地址给updateValue函数,即二级指针
    updateValue(&p);

    printf("After updateValue: %d\n", *p); // 输出指针p所指向的新值:200

    return 0;
}

 

七、指针数组 💫

👉指针数组是指针还是数组呢?

是数组,是存放指针的数组

int* arr3[5];

👉arr3是一个数组,有五个元素,每个元素是一个指针;

 

  • 28
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值