C语言——指针基础

news/2024/12/2 17:43:57/

1 指针基础

怎么获得变量地址

在这里插入图片描述

1   如何产生一个指针变量——>类型* 标识符;int* p1;char* p2;double* p3;//不同类型的基本指针占用内存是一样的都是4个字节(32位)/8个字节(64位),都是存的地址2 数组名是数组首地址但不是普通指针——>数组名绑定的一段内存可以影视转化为指针int array[4] = { 1,2,3,4};printf("array:%zd\n", sizeof(array));//打印16,整个数组的大小printf("array:%p\tarray[0]:%p", array, &array[0]);//值一样,内容不一样3  int*p1;未初始化是野指针p1=NULL;变成空指针。NULL-->(void*)00强制转化地址一般定义指针 int*p=NULL;4 指针取值运算int num=666;int*P=#//*指针变量 ,指针变量[0];printf("%d\t%d\t%d\n", num, *pnum, pnum[0]);//都打印666*pume=888printf("%d\t%d\t%d\n", num, *pnum, pnum[0]);//都打印888//操作指针变量*pume就相当于操作num,任意修改一个其他都会跟着变5 指针偏移——>移动数据位//p+n或者p-n是移动数据位//int* p要明白指针类型//指针的类型:int*  -->去掉变量名//指针的所指向类型:int-->操作的数据的类型-->去掉变量名和*号(基类型)//知道操作的数据类型就知道偏移多少printf("p1=%p\n", p1);     int p1=0000000000000000printf("p2=%p\n", p2);		char p2=0000000000000000printf("p3=%p\n", p3);  	double p3=0000000000000000//+1,偏移一个数据位   printf("p1=%p\n", p1+1);  	int p1=0000000000000004printf("p2=%p\n", p2+1);   char p2=0000000000000001printf("p3=%p\n", p3+1);   double p3=0000000000000008printf("array=%p\n", array);   array=000000A8A24FF4C8printf("array=%p\n", array+1); array=000000A8A24FF4CC //差4int(*p)[3] = NULL;    printf("p=%p\n", p );	  //操作的是int[3]printf("p=%p\n", p + 1);  //int[3]——>偏移一个数组12个字节

2 const与指针变量

const后面不能被修改,把变量变成了常属性。 1.以下两种没区别
const int cnum1 = 0;
int const cnum2 = 0;2.*前面,指针指向内容不可以修改——>修饰1
//以下两种没区别
//const描述的是指针所指向的内容
const int* p1 = &cnum1;
int const* p2 = &cnum1;
int data = 0;
*p1=666;(不行)
p1 = &data;
p1 = p2;(可以)3*后面,指针不可以修改——>修饰2//让指针变量指向的地址固定
int* const p3 = &data;
//const修饰的是p3 不可修改
p3 = p2; (不行)
p2 = p3;(可以)4const int* const p4 = &data;
//都不能被修改

在这里插入图片描述

3 二级指针与多级指针

因为指针变量也有地址,也可以用指针来存放
类似与套娃
int num = 0;
int* p1 = #
int** p2 = &p1;
int*** p3 = &p2;num = 999;
printf("%d\n", ***p3);
printf("%d\n", p3[0][0][0]);//这两个也一样都打印999

4 指针操作一维数组

指针指向数组首地址,直接当数组名去用

1int array[4] = { 1,2,3,4 };int* p = array;//p = &array[0];for (int i = 0; i < 4; i++)
{printf("%d\t", p[i]);		//推荐用法//printf("%d\t", *(p + i));//printf("%d\t", (p + i)[0]);
}//下面用法不推荐,但是要能看懂//改变指针指向,指针偏移到数组之后,任意越界用起来危险while (p != array + 4)
{printf("%d\t", p++[0]);
}printf("\n");2 负下标,不用首地址做初始化int data[10] = { 1,2,3,4,5,6,7,8,9,10 };
int* pp = &data[5];
printf("%d\n", pp[0]);
for (int i = -4; i < 0; i++) 
{printf("%d\t", pp[i]);
}
printf("\n");3  函数传参,传输组名等效于传一级指针(数字类必须还要传长度)在 C 语言中,数组作为函数参数时,实际上是传递数组的首地址,而不是整个数组。因此,函数内部无法直接获取数组的长度。这就是为什么我们需要额外传递数组的长度(元素数量)的原因void print_array(int array[], int arrayNum) 
{for (int i = 0; i < arrayNum; i++) {printf("%d\t", array[i]);}printf("\n");
}
void print_array_2(int *array, int arrayNum)
{for (int i = 0; i < arrayNum; i++){printf("%d\t", array[i]);}printf("\n");
}4 传字符串一定要写const,C语言里可能没有影响,c++有影响(养成好习惯)
int my_strlen(const char* str) 
{int count = 0;while (str[count] != '\0')count++;return count;
}

5 指针操控二维数组

1  一级指针操作二维数组——>列转换为序号void test_one() 
{int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };int* p = &array[0][0];for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {//行列转换为序号printf("%d\t", p[i * 4 + j]);}printf("\n");}2  数组指针操作void test_two() 
{int array[3][4] = { 1,2,3,4,5,6,7,8,9,10,12 };//二维数组名偏移的一行printf("array:%p\n", array);printf("array+1:%p\n", array+1);  //16//二维数组名+一个下标 转换为一个一级指针printf("array[0]:%p\n", array[0]);printf("a rray[0]+1:%p\n", array[0]+1); //4;2.1//推荐用法!!! //数组指针操作二维数组(直接当数组名)int(*p)[4] = array;for (int i = 0; i < 3; i++) {for (int j = 0; j < 4; j++) {printf("%d\t", p[i][j]);}printf("\n");}以下是多种写法,用A换元思想(书本上出现要认识)2.2 for (int i = 0; i < 3; i++){for (int j = 0; j < 4; j++){printf("%d\t", *(*(p+i)+j));//p[i]==>A  A[j]==>*(A+j)//p[i]==>*(p+i)==>A}printf("\n");}2.3		printf("%d\t", *(p[i] + j));//p[i]==>A  A[j]==>*(A+j)//p[i]==>A2.4		printf("%d\t", ((p + i)[0] + j)[0]);//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]//p[i]==>(p+i)[0]==>A2.5		printf("%d\t", (p[i] + j)[0]);//p[i]==>A  A[j]==>*(A+j)==>(A+j)[0]//p[i]==>(p+i)[0]==>A3  函数传参void print_array(int(*p)[4], int row, int cols)
{for (int i = 0; i < row; i++) {for (int j = 0; j < cols; j++) {printf("%d\t", p[i][j]);}printf("\n");}
}
void test_three() 
{int array[3][4] = { 1,2,3,4,5,65,7,8,9,0,19,12 };print_array(array, 3, 4);
}

6 万能指针

#include <stdio.h>
#include <stdlib.h>
int main() 
{//万能指针
void* p = NULL;
int num = 999;
p = &num;//万能指针不能*p直接访问
//要做目标数据类型的强制类型转换
printf("%d\n", *(int *)p);
double dNum = 8.98;
p = &dNum;
printf("%.2lf\n", *(double*)p);return 0;

7 指针函数

#include <stdio.h>
#include <stdlib.h>.	传指针问题1	//值传递void modify_one(int a)  //int a=实参{a = 100;}//没有返回值,打印出来还是0//址传递(函数不需要返回值就可以修改值)
2	//修改实参的值 ,传入实参的地址,修改是*地址void modify_two(int* p) //int* p=实参 {*p = 100;}3	//(为什么传二级指针)修改指针指向num指向g_num,用二级指针接收指针的地址int g_num = 999;void modify_point(int** p)   //int** p=实参{*p = &g_num;}
//——————————————————————————————————————————————
int main(){1 int num = 0;modify_one(num);printf("%d\n", num);
//——————————————————————————————————————————————    2 modify_two(&num);printf("%d\n", num);
//——————————————————————————————————————————————   3	int* p = &num;modify_point(&p);//传入的指针变量printf("%d\n", p[0]);
}
.	返回指针问题1	//C语言不允许返回局部变量的地址(不安全的)//内存会回收,变量地址给其他不知道的东西了//warning C4172: 返回局部变量或临时变量的地址: numint* get_num() {int num = 99999;return &num;(不行)}2 	//需要学会区分什么叫做局部变量的地址int* get_num_one(int* p) {return p;(可以)——>因为在主函数里调用时,变量一直到结束时都是有效的}3	//可以返回堆区内存的地址(下章说)4	//返回一个数组的函数(返回数组首地址就可以了)int array[3] = { 1,2,3 };int* get_array() {return array;}int main() 
{1 int* pp = get_num();printf("%d\n", *pp);printf("%d\n", *pp);
//——————————————————————————————————————————————    2 get_num_one(p);//函数返回指针后还可以的继续操作//p[0];get_num_one(p)[0];//*p=199;*get_num_one(p) = 199;printf("%d\n", g_num);
//——————————————————————————————————————————————4 int* parray = get_array();for (int i = 0; i < 3; i++) {printf("%d\n", parray[i]);}printf("\n");return 0;
}

在这里插入图片描述

!!!这里先看一下指针函数和函数指针的区别,下篇会将到函数指针,容易弄混!!!

在这里插入图片描述

在这里插入图片描述


http://www.ppmy.cn/news/1551807.html

相关文章

git使用记录与总结

目录 前言 一、git是什么&#xff1f; 二、使用记录 1.git安装 2.git clone 3.-lfs初始化 4.git add 5.git commit 6.git push 相关问题与解决 总结 前言 随着Github、hugging face等平台各种开源代码、模型的广泛使用&#xff0c;个人可以使用git方便的下载代码与…

群控系统服务端开发模式-应用开发-前端邮箱短信通道开发

一、添加视图 在根目录下src文件夹下views文件夹下param文件夹下emailsms文件夹下&#xff0c;新建index.vue&#xff0c;代码如下 <template><el-tabs type"border-card"><el-tab-pane v-if"$store.getters.butts.includes(ParamEmailsmsIndex…

Linux常用操作之vim快捷操作

文章目录 前言一、vim三种工作模式二、命令行模式操作三、编辑模式操作四、末行模式操作五、vim快速注释多行操作六、vim快速取消多行注释操作 前言 在使用Linux操作系统时,经常会使用vi/vim编辑文件,会涉及到文件内容的删除、注释、增加等&#xff0c;如果改动的地方较多,那么…

工厂方法模式与抽象工厂模式

首先是一个工厂方法模式&#xff1a; #include <iostream> #include <string> using namespace std;// 抽象产品类 class Car { public:virtual void Run() 0; // 纯虚函数&#xff0c;定义产品接口virtual ~Car() {} // 虚析构函数&#xff0c;保证多态删除 };/…

java——Spring中的Bean线程安全问题

Spring中的Bean对象是否线程安全取决于多个因素&#xff0c;包括Bean的作用域&#xff08;scope&#xff09;、Bean的实现方式以及如何使用这些Bean。以下是一些关键点来帮助理解Spring中Bean的线程安全性&#xff1a; 1. Bean的作用域 Singleton (默认作用域)&#xff1a;在…

Ardupilot开源无人机之Geek SDK讨论

Ardupilot开源无人机之Geek SDK讨论 1. 源由2. 假设3. 思考3.1 结构构型3.2 有限资源3.3 软硬件构架 4.Ardupilot构架 - 2024kaga Update5. 讨论5.1 话题1&#xff1a;工作模式5.2 话题2&#xff1a;关键要点5.3 话题3&#xff1a;产品设计 6. Geek SDK - OpenFire6.1 开源技术…

云原生周刊:K8s 严重漏洞

云原生周刊&#xff1a;K8s 严重漏洞 开源项目推荐 KitOps KitOps 是一款开源的 DevOps 工具&#xff0c;专为 AI/ML 项目的全生命周期管理而设计&#xff0c;通过将模型、数据集、代码和配置打包并版本化为符合 OCI&#xff08;开放容器标准&#xff09;的工件&#xff0c;…

在WSL 2 (Ubuntu 22.04)安装Docker Ce 启动错误解决

查看WSL版本 在 Windows 命令提示符&#xff08;CMD&#xff09;或 PowerShell 中&#xff0c;你可以使用以下命令来查看已安装的 WSL 发行版及其版本信息&#xff1a; wsl -l -v(base) PS C:\Users\Lenovo> wsl -l -vNAME STATE VERSION * Ubuntu-2…