首页 > 其他分享 >C语言的指针详解

C语言的指针详解

时间:2024-03-20 20:59:34浏览次数:21  
标签:变量 指向 int C语言 地址 详解 类型 指针

一、指针的定义及使用

1.指针是什么?

指针是程序数据在内存中的地址,而指针变量是用来保存这些地址的变量。在同一CPU构架下,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。

2.指针的类型及指向类型

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。而再将*去掉,就是这个指针的指向的类型。 

#include<stdio.h>
int main()
{
    int *ptr;//指针的类型是 int*,指针所指向的类型是 int
    char *ptr;//指针的类型是 char*,指针所指向的的类型是 char
    int **ptr;//指针的类型是 int**,指针所指向的的类型是 int*
    int (*ptr)[3];//指针的类型是 int(*)[3],指针所指向的的类型是 int()[3]
    int *(*ptr)[4];//指针的类型是 int*(*)[4],指针所指向的的类型是 int*()[4]
}

 3.关于指针的的算术运算

指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的,以指针所指向的类型的字节数为单位。

#include <stdio.h>
int main()
{
	int i = 10;
	char* a1 = (char*)&i;
	int* a2 = &i;
	printf("%p\n", &i);
	printf("%p\n", a1);
	printf("%p\n", a1 + 1);
	printf("%p\n", a2);
	printf("%p\n", a2 + 1);
	return 0;
}

看来答案显而易见,指针变量与整数的运算与指针类型有关,char*类型的指针指向的是char,故跳过一个字节,int*类型的指针指向的是int,故跳过四个字节。

那么我们还有有一个疑问,指针能否可以和指针进行加减?

请看下面的代码。

#include<stdio.h>
int main()
{
	int i = 0;
	int* p = &i;
	int* o = p + 1;
	printf("%d", p - o);
	return 0;
}

 

 指针与指针的相减,是在指针类型相同的前提下成立的。它的结果为什么是-1?这是因为p+1之后,内存地址上向高地址的方向移动了四个字节,而结合指针类型是int*,然后移动的字节数要除以4(int类型占四个字节),所以结果就为-1。

两个指针不能进行加法运算,这是非法操作,因为进行加法后,得到的结果指向一个不知所向的地方,这会有安全隐患。

4.取地址操作符&和解引用操作符*

这里&是取地址操作符,*是解引用操作符。

变量会存放在内存空间,这个时候为了得到变量的地址,就需要&取地址操作符。&a 的运算结果是一个指针,指针的类型是 a 的类型加个 *,指针所指向的类型是 a 的类型,指针所指向的地址,就是 a 的地址。

&a取出的是a所占4个字节中地址较⼩的字节的地址。(int类型占四个字节)

在现实⽣活中,我们使⽤地址要找到⼀个房间,在房间⾥可以拿去或者存放物品。
C语⾔中其实也是⼀样的,我们只要拿到了地址(指针),就可以通过地址(指针)找到地址(指针)指向的对象。 *p 的结果是p 所指向的东西,这个东西有这些特点:它的类型是 p 指向的类型,它所占用的地址是 p 所指向的地址。指针的类型决定了,对指针解引用的时候有多大的权限(⼀次能操作几个字节)。

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

 

二、指针与其他类型的关系

1.数组与指针的关系

数组名的意义:
1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。
2. &数组名,这里的数组名表示整个数组,取出的是整个数组的指针。
3. 除此之外所有的数组名都表示首元素的指针。


数组指针存放的是数组的地址,能够指向数组的指针变量。
 

int (*p)[5];

 p先和*结合,说明p是⼀个指针变量,然后指向的是⼀个大小为5个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。

2.指针与函数的关系

函数指针变量应该是⽤来存放函数地址的,未来通过地址能够调⽤函数的。
 

int fun(char *,int);
int (*p)(char *,int);
p=fun;
int a=(*p)("abcdef",6); //通过函数指针调用函数。

除了上文的数组名,函数名也是一个指针。不过它们也有些差异,数组名前加&,是取整个数组的指针,而函数名前加&,还是取的是函数指针。 

3.指针与结构体类型的关系

struct MyStruct
{
    int a;
    int b;
    int c;
};
struct student s={10,20,30};
//结构对象s,并把s的成员初始化为10,20 和30。
struct student *ptr=&s;
//一个指向结构对象s的指针。它的类型是student*,它指向的类型是student。
int *pstr=(int*)&s;
//一个指向结构对象s的指针。但是pstr和它被指向的类型ptr 是不同的。

那么如何访问结构体的成员,结构体成员的直接访问是通过点操作符(.)访问的。而间-接访问是用操作符(->) 访问的。(结构体变量.成员名、结构体指针->成员名)

s.a//直接访问
ptr->a//间接访问
*pstr; //访问了s的成员a。
*(pstr+1); //访问了s的成员b。
*(pstr+2) //访问了s的成员c。

上面还有一个指针pstr,用这样的方式去访问是错误的。为什么是错误的?因为存放结构对象的各个成员的时候,需要遵循对齐规则,它不同于数组在内存中的连续存放,可能会存在空隙,导致非法访问。
 

三、指针的正确使用

1.野指针

野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)指针变量在定义时如果未初始化,其值是随机的,指针变量的值是别的变量的地址,意味着指针指向了一个地址是不确定的变量,此时去解引用就是去访问了一个不确定的地址,所以结果是不可知的。

产生野指针的原因有哪些?

指针变量未初始化:任何指针变量刚被创建时不会自动成为NULL指针,它的值是随机的。

指针越界访问:当指针指向的范围超出数组的范围时,它很可能会指向随机值。

指针操作超越变量作用域:不要返回指向栈内存的指针或引用,因为栈内存在函数结束时会被释放。

2.如何规避野指针

如果明确知道指针指向哪⾥就直接赋值地址,如果不知道指针应该指向哪⾥,可以给指针赋值NULL。NULL 是C语⾔中定义的⼀个标识符常量,值是0,0也是地址,这个地址是⽆法使⽤的,读写该地址会报错。

用assert()断言来验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运⾏,否则就会终⽌运⾏,并且会给出报错。

绝不返回局部变量和局部数组的地址,任何使用与内存操作相关的函数必须指定长度信息。

四、多级指针

指针变量也是变量,它同样有地址。所以存放指针变量的指针就是二级指针。

定义指针时,一级指针有一个*,二级指针加两个*,三级指针加三个*,以此类推。

int a =100;
int *p1 = &a;//一级指针
int **p2 = &p1;//二级指针

 想要获取指针指向的数据时,一级指针加一个*,二级指针加两个*,三级指针加三个*,以此类推

标签:变量,指向,int,C语言,地址,详解,类型,指针
From: https://blog.csdn.net/z6665454/article/details/136854470

相关文章

  • Java中String类型的创建与比较(详解)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、String类型是什么??二、String类型的创建使用字符串字面量使用new关键字intern()方法简读图解String的比较总结前言提示:这里可以添加本文要记录的大概内容:在背八股文(Holis版)的过程中遇......
  • 贪心算法详解
    贪心1建立数学模型来描述问题2把求解的问题分成若干个子问题3对每一个子问题求解,得到子问题的局部最优解4把子问题的解局部最优解合成原来解问题的一个解总结:局部最优做到全局最优。例题实战1在很久以前,有n个部落居住在平原上,依次编号为1到n,第i个部落的人数为ti,......
  • C语言——复制字符串
    题目描述:有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。输入:数字n,一行字符串,数字m。输出:从m开始的子串。代码如下:代码一:#include<stdio.h>#include<stdlib.h>intmain(){intn,i=0,j,m;charc[20];......
  • 你真的了解c语言的10大字符串函数吗?
    乐观学习,乐观生活,才能不断前进啊!!!我的主页:optimistic_chen我的专栏:c语言点击主页:optimistic_chen和专栏:c语言,创作不易,大佬们点赞鼓励下吧~前言:长度不受限制的字符串函数-strcpy,strcat,strcmp长度受限制的字符串函数-strncpy,strncat,strncmp文章目录前言:1.st......
  • 拿捏指针(三)
    ✨✨欢迎......
  • 【leetcode】135_candy糖果题_贪心算法_C语言_唐完了之后是?(雾
    原题如下:(蓝字为原题链接,可跳转查看)135.分发糖果n 个孩子站成一排。给你一个整数数组 ratings 表示每个孩子的评分。你需要按照以下要求,给这些孩子分发糖果:每个孩子至少分配到 1 个糖果。相邻两个孩子评分更高的孩子会获得更多的糖果。请你给每个孩子分发糖果,计算并......
  • C语言游戏实战(4):人生重开模拟器
     前言:人生重开模拟器是前段时间非常火的一个小游戏,接下来我们将一起学习使用c语言写一个简易版的人生重开模拟器。 网页版游戏:人生重开模拟器(ytecn.com)1.实现一个简化版的人生重开模拟器(1)游戏开始的时候,设定初始属性:颜值,体质,智力,家境(2)开始游戏,随机生成性别和出生......
  • MySQL varchar详解
    ......
  • 个人App上架步骤详解
    ​ 想要成功将个人开发的App上架到应用商店,需要经过一系列关键步骤,包括注册开发者账号、准备应用材料、提交审核等。以下将对这些步骤进行详细介绍。   ​一、注册开发者账号在将应用程序发布至应用商店之前,开发者需要注册开发者账号。目前,主要的应用商店包括苹果App......
  • nmap 参数详解。
    #读取文件扫描,一行一个,可以是主机名或者网段。nmap-iLtarget.txt#随机选择5个目标进行扫描。模拟对网络中随机主机的扫描,以便评估网络安全性。nmap-iR5#排除在扫描范围之外的主机或网络。nmap192.168.1.0/24--exclude192.168.1.1nmap192.168.1.0/24--exclude19......