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

C语言指针详解-上

时间:2024-08-15 11:55:37浏览次数:18  
标签:p2 10 p1 int C语言 地址 详解 指针

C语言指针详解-上

前言

指针是C语言中一个绕不开的点,也是解题必备的工具,本文将围绕指针这几点进行详解:

  • 指针的基本概念
  • 指针类型
  • 指针运算
  • 指针的用途
  • 指针的安全隐患和解决方法
  • 常用工具

1.指针的基本概念

1.1指针是什么

在C语言中,任何变量的创建都需要在内存中申请空间,而这些空间都有特定的编号,即地址,也称作指针

地址也是一串数字,用于存放地址的变量就是指针变量,我们平常说的指针就是这个指针变量

1.2指针的声明与初始化

  • 在C语言中,声明指针主要分两步:
  • 使用解引用符(*)表明声明的变量是个指针
  • 指定一个指针指向的数据类型

如:

int* p1,p2;

*表明p1是个变量,int表明p1可以存储指向整型变量的地址
对于p2*和它没有关系,所以p2是个整型变量

  • 而在声明指针时,给指针一个具体的地址NULL就是初始化

如:

int x = 10; 
int *p = &x; 

这里创建了变量x,并使用取地址符(&)将x的地址存入p

1.3取地址符&和解引用符*

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

在之前的学习中,我们应该多次使用了&:

int x;
scanf("%d", &x);

是的,当使用scanf函数读取变量,我们其实传递了变量的地址,这样scanf函数才能正确地将读取到的数据存储到那个变量中。

* 运算符用于访问指针指向的值

如:

int x = 10; 
int *p = &x; 
printf("%d",*p);

p是一个指向x的指针,那么*p就是x的值
我们也可理解为*获取了p中存放的地址,并通过这个地址找到了变量x

2.指针的类型

指针的类型大多取决它所指向的数据类型:

常见数据类型的指针

int *p1;
double *p2;
char *p3;

p1指向整型
p2指向双精度浮点型
p3指向字符

指针与数组、字符串

数组名大多情况下是指向数组首元素的指针:

int arr[10]={1,2,3,4,5,6,7,8,9,10};
for(int i=0;i<10;i++)printf("%d ",*(arr+i));
int* pa=arr;
for(int i=0;i<10;i++)printf("%d ",*(pa+i));

在这里插入图片描述
字符串实际上是一个字符数组,后面跟着一个空字符’\0’作为结束标志
因此,字符串的名字也是第一个字符的地址:

char ch[] = "Hello World!\n";
printf(ch);
char *pc = ch;
printf(pc);

在这里插入图片描述

数组指针

数组指针是指向一个具有固定数量元素的数组的指针。
因为只有元素数量固定,数组类型才能被确定:

int arr[10];     arr是个数组,元素个数10,元素类型为整型
int (*p1)[10];    p1是个指针,指向数组元素个数10,元素类型为整型
int (*p2)[10] = &arr;这是数组指针的初始化
p1 = &arr;这是数组指针的赋值

注:&数组名取出的是整个数组的地址

arr/&arr[0]&arr
数组首元素的地址整个数组的地址
类型int*int(*)[10]

结构体指针

声明和初始化的过程大同小异:

struct Stu
{
	int a;
	char c[20];
};
struct Stu S1;
struct Stu* p1;  声明
struct Stu* p2 = &S1;   初始化

需注意,当通过指针访问结构体成员时,可使用箭头运算符 ->,也可使用解引用符*

struct Stu S2={1,"Hello world!"};
p1 = &S2;
printf("%d\n",(*(p1)).a);
printf("%s\n",p1->c);

在这里插入图片描述

函数指针

函数名&函数名都是其地址,存放函数地址的变量就是函数指针:

int Add(int a,int b){return a + b;}
int (*p1)(int,int);   声明
int (*p2)(int,int) = &Add;初始化
int (*p3)(int,int) = Add; p2与p3相同

可以看见,函数指针声明也分两步:

  • 使用解引用符(*)表明声明的变量是个指针
  • 指定一个指针指向的函数类型

函数类型就是:返回类型(参数类型1,参数类型2…)
int(int,int)
其函数指针类型就是int(*)(int,int)

二级指针

指针变量也是一种变量,创建时会在内存开辟空间,而存储指针变量的地址的变量就是二级指针

int *p1;
int* *p2 = &p1;

其中,*p2*表明p2是个指针,int*表明p2指向指针变量,= &p1p1的地址存入p2

void指针

即以void声明的指针,无具体类型,可根据需要强制类型转换成所需的类型。
需注意,不强转就不能解引用

	int a = 0;
	void* p = &a;
	*p = 10;

在这里插入图片描述
在这里插入图片描述
但是可以直接使用其存储的地址,但可能有警告

	char c[20] = "Hello World!";
	void* p = c;
	printf("%s\n", p);

在这里插入图片描述
在这里插入图片描述

3.指针运算

前面我讲了指针的类型,而指针的类型在指针运算中起了关键作用

指针运算主要包括:

  • 指针的解引用
  • 指针 + 整数、指针 - 整数
  • 指针和指针的比较
  • 指针-指针

3.1指针的解引用

指针类型决定了其在解引用时访问几个字节,以及访问的方式

	int n1 = 0x66666666;
	int n2 = 0x66666666;
	int n3 = 0x66666666;
	int* p1 = &n1;
	*p1 = 0;
	char* p2 = (char*) & n2;
	*p2 = 0;
	float* p3 = (float*) & n3;
	*p3 = 0;
	printf("int:%x\nchar:%x\nfloat:%x\n", n1,n2,n3);

在这里插入图片描述

3.2指针 + 整数、指针 - 整数

指针加整数n,其储存的地址加(n* 所指类型的大小),单位字节
可简单验证:

	char ch;
	int a;
	int arr[4] = { 0 };
	char* pc = &ch;
	int* pa = &a;
	int(*parr)[4] = &arr;
	printf("pc=%p\npa=%p\nparr=%p\n", pc, pa, parr);
	printf("pc=%p\npa=%p\nparr=%p\n", pc+1, pa+1, parr-1);

在这里插入图片描述

3.3指针和指针的比较

在两个指针指向同一块空间的不同位置,我们可以进行指针间的比较:

int arr[10]={1,2,3,4,5,6,7,8,9,10};
int*p1=arr;
int*p2=&arr[9];
while(p1<=p2)
{
	printf("%d ",*p1);
	p1++;
}

在这里插入图片描述

3.3指针-指针

相同类型指针可相减,得到相距的元素个数
下面代码使用指针-指针得到字符串长度:

	char ch[10] = "Hahaha";
	char* pc1 = ch;
	char* pc2 = ch;
	while (*pc2 != '\0')pc2++;
	printf("%d\n", pc2 - pc1);

在这里插入图片描述

希望本篇文章对你有所帮助!
当然,本人仅仅是个C语言初学者,如有任何意见,欢迎各位提出!

C语言指针详解-下

标签:p2,10,p1,int,C语言,地址,详解,指针
From: https://blog.csdn.net/2401_86587256/article/details/141144120

相关文章

  • 恶补基础知识:Java 栈与队列详解
    @目录前言简介栈Java实现栈的示例代码:栈的主要应用场景包括:队列Java实现队列的示例代码:LinkedList中的add方法和offer方法的区别队列主要应用场景:总结前言请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i、提示:以下是本篇文章正文内容,下面案例可供参考简介使用Java实......
  • PCIe扫盲:Memory & IO 地址空间/基地址寄存器详解/Base & Limit寄存器详解
    转载:PCIe扫盲:Memory&IO地址空间/基地址寄存器详解/Base&Limit寄存器详解-极术社区-连接开发者与智能计算生态(aijishu.com)Memory&IO地址空间早期的PC中,所有的IO设备(除了存储设备之外的设备)的内部存储或者寄存器都只能通过IO地址空间进行访问。但是这种方式局限性......
  • C语言结构体内存对齐
    结构体或许小伙伴们都知道,或许也能够做到熟悉的去运用结构体,但你们有没有想过:整型数组存放的数据都是整型,字符数组存放的数据都是字符,它们类型相同,所以也都能够做到在内存中紧密的存储,而结构体中存放的数据各种各样,它们的存储是否能做到在内存中紧密排列呢?又或者说,结构体的内存......
  • 神经网络之卷积篇:详解三维卷积(Convolutions over volumes)
    详解三维卷积从一个例子开始,假如说不仅想检测灰度图像的特征,也想检测RGB彩色图像的特征。彩色图像如果是6×6×3,这里的3指的是三个颜色通道,可以把它想象成三个6×6图像的堆叠。为了检测图像的边缘或者其他的特征,不是把它跟原来的3×3的过滤器做卷积,而是跟一个三维的过滤器,它的维......
  • 【C语言】sizeof 和 strlen
    sizeof和strlen的对比sizeof在学习操作符的时候,我们学习了sizeof,sizeof计算变量所占内存内存空间大小的,单位是字节。如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间的大小。sizeof只关注占用内存空间的大小,不在乎内存中存放什么数据。比如:#include......
  • C语言发展史
    在线书籍:54笨鸟1.C语言发展史任何一种新事物的出现都不是来自于偶然,而是时代所驱使的必然结果。1.1C语言有多伟大如果你问我:C语言有多伟大。那么,我可能会想一下,说:多伟大我不知道,但是我知道很伟大。这里,我想说一句可能有点片面的话,就是:如今这世界上,凡是带电的地方,可能......
  • 初学者如何学c语言
    你对学习如何编程感兴趣吗?如果是的话,你从C语言编程开始是不会错的。C语言是一种通用的、强大的、广泛使用的编程语言,可用于构建操作系统、开发视频游戏,甚至创造机器人。然而,对于初学者来说,学习C语言编程可能是令人生畏的。这就是为什么我们把这个初学者指南放在一起,让你开......
  • C语言中水平制表符 \t 与退格键 \b 的使用方法探索
    经个人实践,C语言中使用转义序列码(\t)会输出一个8个格数的组合,当\t之前的内容达到8*n格时,后续内容出现在8*(n+1)+1格。(式中n>=1,且为整数)探索过程如下:第一次在看到某大佬的科普中提到:\b将输出位置左移一位\t表示一个tab的距离即1个大空格,相当于4个小空格......
  • 深入了解指针(8)
    文章目录1.sizeof和strlen的对⽐1.1sizeof1.2strlen1.3sizeof和strlen的对⽐2.数组和指针笔试题分析2.1一维数组2.2字符数组2.3⼆维数组3.指针运算笔试题分析1.sizeof和strlen的对⽐1.1sizeof在学习操作符的时候,我们学习了sizeof,sizeof计算变量所占......