【C语言】指针总结

本文详细介绍了C语言中的指针概念,包括不同类型的指针、指针运算和常见问题。重点讨论了野指针的成因及如何避免,如未初始化、越界访问和指向已释放内存的问题。此外,还涵盖了指针与数组的关系以及在参数传递中的应用。
摘要由CSDN通过智能技术生成

上述p1与p2就是两个指针变量,先看p1,p1变量的类型是 int*, int* 就代表它是一个一级指针。

再看p2,p2变量的类型是int**,有两颗星,就代表这是个二级指针,再看它的值是 &p1,是取的一级指针的内存地址。也就是说,1. 二级指针 指向的是一个 一级指针; **2.**一级指针指向的是基本数据类型,int、char、short等。

[](()二、野指针的概念


[](()1、概念

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

[](()2、成因

a. 指针未初始化,如下

int main()

{

int a = 10;

int* p1 = &a; //正确,把a的内存地址赋值给p1

int* p2; //错误,未初始化,若直接进行访问,会报错

return 0;

}

b. 指针越界访问,如下

int main()

{

int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int* p = arr; //数组名,首元素地址

for (int i = 0; i < 11; i++)

{

printf("%d ",*(p+i)); //数组元素共10个,最后一个元素的下标是9,i变量能够等于10,越界

printf("%d ",arr[i]); //此处两个printf函数的作用,等价

}

return 0;

}

c.指针指向的内存空间已经被释放,如下

struct Student

{

char name[20];

int age;

};

int main()

{

//创建一个结构体,返回的是指向 struct Student类型的指针变量 s1

struct Student* s1 = (struct Student*)malloc(sizeof(struct Student));

//假设现在我们不需要这块空间了,在C/C++中,malloc申请的内存空间需要程序员自己手动释放(回收)

free(s1);

//现在s1已经被释放(回收)了,意思是 由变量s1指向的这块内存空间还给了系统

//但是s1里面还是保存着这块内存空间(struct Student)的内存地址(可理解为房间号)

//如果此时再次去访问这块空间,那就会出错的。因为这块空间已经回收了

s1->name = “博尔特”; //错误,内存空间已经回收,这也称为也指针

return 0;

}

[](()3、如何规避上诉问题?

有人说:“不使用指针,就完美的规避了”。 那不可能啊,衡量一个C/C++程序员的技术水平,指针的运用占了不小的份额。

  • 指针初始化

  • 小心指针越界访问

  • 指针指向的空间释放后,及时置为NULL

  • 指针使用之前检查有效性

[](()三、六大基本指针类型


[](()1、char*

char ch = ‘A’;

char* p = &ch; //将ch的内存地址赋值给p

[](()2、short*

short a = 1314;

short* p = &a; //将a的内存地址赋值给p

[](()3、int*

int a = 10;

int* p = &a; //将a的内存地址赋值给p

[](()4、long*

long a = 100000;

long* p = &a; //将a的内存地址赋值给p

[](()5、float*

float a = 3.0;

float p = &a; //将a的内存地址赋值给p

[](()6、double*

double a = 5.0;

double* p = &a; //将a的内存地址赋值给p

[](()四、指针运算


[](()1、& 与 *

&: 取地址符,可以取出变量在内存中的地址。

示例: &number, 取出number变量的内存地址

**:**间接访问操作符,也叫解引用,不要与二元运算符()混淆,二者符号相同,但语法不同。

int main()

{

int a = 20;

int* p = &a; //取a的地址

printf(“%d\n”,*p); //通过指针p,进行解引用,去输出a的值

return 0;

}

[](()2、指针 ± 整数

int main()

{

char arr1[5] = {‘a’,‘b’,‘c’,‘d’,‘e’};

int arr2[5] = {1, 2, 3, 4, 5};

char* p1 = arr1;

int* p2 = arr2;

for (int i = 0; i < 5; i++)

{

printf("%c ",*(arr1 + i));

}

for (int i = 4; i >= 0; i–)

{

printf("%d ", *(arr2 + i));

}

return 0;

}

上诉代码输出的结果是

a b c d e

5 4 3 2 1

char类型的变量占一个字节的空间,int类型的变量占四个字节的空间。而两个指针变量p1和p2也能够加减一个整数去读取内存中的数据。

也就是说,int* 的指针p2 + 1 ,并不是向后访问一个字节空间,而是访问的int类型的4个空间。例如:short* 的指针变量 p+1,向后访问的是short类型的2个空间,如下图int*类型指针加减的过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4KIv7Zh-1622041026120)(asserts/%E5%8A%A8%E7%94%BB.gif)]

[](()3、指针 - 指针

int my_strlen(char *s) {

char *p = s;

while(*p != ‘\0’ )

p++;

return p-s;

}

int main()

{

int a = 10;

int b = 20;

int* p1 = &a;

int* p2 = &b;

printf(“%d\n”, p2 - p1);

printf(“%d\n”, p1 - p2); 高地址 减 低地址 再+1,得到的是两块内存空间之间的内存空间个数

return 0;

}

[](()4、const int* p 与 int* const p

int a = 10;

const int* p = &a;

int* const p = &a;

第一个:const int* p = &a; const关键字是修饰的是 *p,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZQqKgkrB-1622041026121)(asserts/%E5%8A%A8%E7%94%BB1-1622037903111.gif)]

在这里插入图片描述

第二个:int* const p = &a;这次const关键字修饰的 p,而不是*p。如图

在这里插入图片描述

在这里插入图片描述

综上所诉,谁写在const的后面就是修饰谁,谁就不能改动。

const int* p = &a; 此时 *p = 20; 不可取 ,* p被修饰

int* const p = &a; 此时 p = &b; 不可取,p被修饰

[](()五、指针与数组


[](()1、指针数组

中心意思是一个数组,这个数组里面的每一个元素是指针类型的变量

int a = 10;

int b = 20;

int* arr[2] = { &a, &b}; //这就是一个指针数组

[](()2、数组指针

中心意思是一个指针,这个指针指向的是一个数组的空间。

//第一种情况

int arr[3][3] = {{1,2,3},{3,4,5},{5,6,7}};

int (*parr)[3] = arr; //此处的arr是二维数组的首元素地址,这个地址是{1,2,3}这个一维数组的地址

//第二种情况

int arr2[3] = {7,8,9};

int (*parr2)[3] = &arr; //此处取出的是arr这整个数组的地址,注意区分二者

[](()3、一维数组传参

#include <stdio.h>

void test(int arr[])//ok

{}

void test(int arr[10])//ok

{}

void test(int *arr)//ok

{}

void test2(int *arr[20])//ok

{}

void test2(int **arr)//ok

{}

int main()

{

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值