(c)深入了解指针

本文详细介绍了C语言中的指针概念,包括指针类型、指向的类型、取地址与解引用、void*指针、const修饰、指针运算、野指针的来源与规避,以及传值调用与传址调用的区别。帮助读者全面掌握指针在编程中的应用。
摘要由CSDN通过智能技术生成

1.前言:类型解析

这里是引用:
int p; //这是一个普通的整型变量
int p; //首先从P 处开始,先与结合,所以说明P 是一个指针,然后再与int 结合,说明指针所指向的内容的类型为int 型.所以P是一个返回整型数据的指针
int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数组,然后与int 结合,说明数组里的元素是整型的,所以P 是一个由整型数据组成的数组
int p[3]; //首先从P 处开始,先与[]结合,因为其优先级比高,所以P 是一个数组,然后再与结合,说明数组里的元素是指针类型,然后再与int 结合,说明指针所指向的内容的类型是整型的,所以P 是一个由返回整型数据的指针所组成的数组
int (p)[3]; //首先从P 处开始,先与结合,说明P 是一个指针然后再与[]结合(与"()"这步可以忽略,只是为了改变优先级),说明指针所指向的内容是一个数组,然后再与int 结合,说明数组里的元素是整型的.所以P 是一个指向由整型数据组成的数组的指针
int **p; //首先从P 开始,先与
结合,说是P 是一个指针,然后再与*结合,说明指针所指向的元素是指针,然后再与int 结合,说明该指针所指向的元素是整型数据.由于二级指针以及更高级的指针极少用在复杂的类型中,所以后面更复杂的类型我们就不考虑多级指针了,最多只考虑一级指针.
int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入()里分析,说明该函数有一个整型变量的参数,然后再与外面的int 结合,说明函数的返回值是一个整型数据
Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与()结合,说明指针指向的是一个函数,然后再与()里的int 结合,说明函数有一个int 型的参数,再与最外层的int 结合,说明函数的返回类型是整型,所以P 是一个指向有一个整型参数且返回类型为整型的函数的指针
int (p(int))[3]; //可以先跳过,不看这个类型,过于复杂从P 开始,先与()结合,说明P 是一个函数,然后进入()里面,与int 结合,说明函数有一个整型变量参数,然后再与外面的结合,说明函数返回的是一个指针,然后到最外面一层,先与[]结合,说明返回的指针指向的是一个数组,然后再与结合,说明数组里的元素是指针,然后再与int 结合,说明指针指向的内容是整型数据.所以P 是一个参数为一个整数据且返回一个指向由整型指针变量组成的数组的指针变量的函数.

2.指针

含义:指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。举个例子,来仔细理解一下。

(1)int*ptr;
(2)char*ptr;
(3)int**ptr;
(4)int(*ptr)[5];
(5)int*(*ptr)[2];

(1)指针类型

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:
(1)intptr;//指针的类型是int
(2)charptr;//指针的类型是char
(3)intptr;//指针的类型是int
(4)int(ptr)[5];//指针的类型是int()[5]
(5)int*(ptr)[2];//指针的类型是int(*)[2]

(2)指针指向的类型

当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。
从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:

(1)int*ptr; //指针所指向的类型是int
(2)char*ptr; //指针所指向的的类型是char
(3)int**ptr; //指针所指向的的类型是int*
(4)int(*ptr)[5]; //指针所指向的的类型是int()[5]
(5)int*(*ptr)[2]; //指针所指向的的类型是int*()[2]

(3)指针的值----或者叫指针所指向的内存区或地址

以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?(重点注意

上述是我仿照其他博主内容写的,这个内容写的真的是重要且通俗易懂。

3. 指针变量和地址

(1)取地址操作符(&)

变量创建的本质是:在内存中开辟一块空间。

(2)指针变量和解引用操作符(*)

a:指针变量也是一种变量,这种变量就是用来存放地址的,存放在指针变量中的值都会理解为地址。
b:C语言中,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向对象,这里要用到解引用操作符。
eg:

#include <stdio.h>
int main(){
int a = 100;
int *pa = &a;  //*p;//解引用操作(间接访问)*p等于a
 *p = 0;  //*pa的意思就是通过pa来存放的地址,找到指向的空间,*pa其实                就是a变量了,所以*a就是a变量;所以*pa = 0,这个操作就是把a改成0了。
 

4.指针变量类型的意义

(1)指针的解引用

结论:指针类型决定了指针进行解引用操作时候访问多大空间
//int *的指针类型解引用访问4个字节。
//char *的指针类型解引用访问1个字节。

(2) 指针+ -整数

char类型的指针变量+1跳过一个字节,int类型的指针变量+1跳过四个字节。
== 结论:1.指针类型决定了指针的步长,就是向/向后走一步多大的距离。(2)p+i 是跳过了i个type类型数据相当于跳过了i*sizeof(type)个字节 。 ==

5.void*指针

在指针类型中有种特殊void类型的,可以理解为无其体类型数据(或者叫泛型指针),这种指针可以接收任意类型的地址。但也有局限性,**void类型的指针不能直接进行指针的±整数和解引用运算。**
一般void*类型的指针是使用在函数参数的部分,用来接收不同类型的地址。

6.const修饰指针

(1)const修饰变量

const是常属性——不能被修改了。

(2)const修饰指针变量

一般来讲const修饰指针变量,可以放在 * 左边,也可以放在 * 右边,意义不一样。
//1.const 放在左边:限制的是*p,意思是不能通过p来改变p指向的对象内容,但p本身是可以改变的,p指向其他对象。
//1.const 放在有边:限制的是p,意思是不能修改p本身的值,但p指向的对象的内容可以被修改。

7.指针运算

指针的基本运算有三种:指针+ -整数; 指针-指针;指针的关系运算。

(1)指针 - 指针

得到指针与指针的元素个数:绝对值|指针 - 指针 |= 个数;
运算条件:两个指针指向了同一块空间。
eg:

#include <stdio.h>
int my_strlen(char * )
{
char * p = s;
while(*p !='\0')
p++;
return p - s;
}
int main()
{
printf("%d \n",my_strlen("abc"));
return 0;
}

(2)指针的关系运算

eg:
//指针的关系运算
#include <stdio.h>
int main()
{
 int arr[10] = {1,2,3,4,5,6,7,8,9,10};
 int *p = &arr[0];
 int i = 0;
 int sz = sizeof(arr)/sizeof(arr[0]);
 while(p<arr+sz) //指针的⼤⼩⽐较
 {
 printf("%d ", *p);
 p++;
 }
 return 0;
}

指针的关系运算解析

8.野指针

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

(1)指针未初始化

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

(2)指针越界访问

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

(3)指针指向的空间释放

#include <stdio.h>
int* test()
{
 int n = 100;
 return &n;
}
int main()
{
 int*p = test();
 printf("%d\n", *p);
 return 0;

(4) 如何规避野指针

a.指针初始化

#include <stdio.h>
int main()
{
 int num = 10;
 int*p1 = &num;
 int*p2 = NULL;
 
 return 0;
}

b:⼩⼼指针越界.
c:指针变量不再使⽤时,及时置NULL,指针使⽤之前检查有效性.

9. 传值调用和传址调用

传址调⽤,可以让函数和主调函数之间建⽴真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采⽤传值调⽤。如果函数内部要修改主调函数中的变量的值,就需要传址调⽤。
传值调⽤:变量本⾝直接传递给了函数。

总结:

 你看完我这篇文章,基本对指针的了解应该会加深。喜欢我的文章可以点赞,收藏哈!!!!!
  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懒羊羊大王&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值