C语言基础之指针(c语言指针讲解)
yund56 2025-05-08 16:41 58 浏览
概述
系统为内存的每一个字节 分配一个32位的地址编号
指针 就是内存的编号
指针变量:本质是变量 只是该变量 保存的是内存的地址编号(不是普通的数值)
&为变量取地址
1、指针变量的定义
(1)指针的定义
int num = 20;
p为20的内存地址即&num
*p = 20
p = &num
注意:如果对num的地址取地址,即**q == *p == 20,那么 * q == p == &num
(2)定义步骤
*修饰指针变量名( * p)
保存谁的地址 就先定义谁。
1 定义一个指针变量p 保存 int num的地址; int *p;
2 定义一个指针变量p 保存数组int arr[5]首地址; int (*p)[5]
3 定义一个指针变量p 保存函数的入口地址 int fun(int,int); int (*p)(int,int);
4 定义一个指针变量p 保存结构体变量的地址 struct stu lucy; struct stu *p;
5 定义一个指针变量p 保存指针变量int *p的地址 int **p
(3)指针变量的详解
在32位平台任何类型的指针变量 都是4字节
在64位平台任何类型的指针变量 都是8字节
p等价于&num
*p等价于num的值 表示取p保存的地址编号的内容
(4)指针使用
int num = 10;
int *p = NULL;//定义一个指针
p = & num;(5)指针的指针
int num = 10;
int *p = #
int **q = &p;n级指针变量 可以保存 n-1级的地址
*p---->num
**q---->num
2、指针变量的初始化
(1)指针变量在操作之前必须指向合法地址空间,指针变量如果不初始化 立即操作 会出现段错误
(2)指针变量如果没有指向合法空间 建议初始化为NULL
int *p = NULL;(3)将指针地址变量初始化为合法地址(变量地址、动态申请的地址、函数入口地址)
int num = 10;
int *p = & num;
等价于
int num = 10, *p = & num;
3、指针变量类型
(1)指针变量自身的类型
指针变量自身的类型 一般用于赋值语句的判断
char *p ---->char *
int *p ---->int *
short *p ---->short *
float *p ---->float *
double *p ---->double *
long *p ---->long *
void test()
{
int num = 10;
int *p = #
//在使用中
//num 为int &num 为int * ‐‐‐‐>对变量名 取地址 整体类型加一个*
//p 为int * *p 为int ‐‐‐‐>对指针变量 取* 整体类型减一个*
//在使用中 &和*相遇 从右往左 依次抵消
*&p == p
} (2)指针变量指向的类型
指针类型指向类型决定取值宽度
char *p ----->char 1B
int *p ----->int 4B
short *p ---->short 2B
float *p ---->float 4B
double *p ---->double 8B
long *p ---->long 4B
案例:
定义一个变量 num = 0x01020304 ,取出其中的02(内容的存取是倒着存倒着取)
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num = 0x01020304;
char *p = (char *)#
printf(“%#x\n”,*(p+2));
return 0;
}取出0203
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num = 0x01020304;
char *p = (char *)#
printf(“%#x\n”,*(short *)(p+1));
return 0;
}(3)*p等价于num
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num = 0;
int *p = #
scanf("%d",p);
printf("num=%d\n",num);
*p = 10;
printf("num=%d\n",num);
(*p)++;
printf("num=%d\n",num);
return 0;
}(4)指针变量的注意事项
①void不能定义普通变量
void num;错误
②void *可以定义指针
void *p;//可以定义p自身类型为void *,在32为平台任意类型的指针 为4B那么系统知道P开辟4B空间,所以定义成功
p就是万能的一级指针变量,可保存任何一级指针地址
万能指针一般用于函数的形参 达到算法操作多种数据类型的目的
注:不要直接对void p的指针变量 取
int num = 10;
void *p = & num;
*p;//错误 p指向的类型为void 无法确定p的取值宽度
对p取*之前对p先进行指针类型强转
强转*(int *)p
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num = 10;
void *p = #
//*p;错误
printf("%d",*(int *)p);//使用前进行强转
}③指针变量 未初始化 不要取*
int *p = NULL;
*p;错误④指针变量不要越界访问
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5] = {1,2,3,4,5};
int *p = arr;
printf(“%d\n”,*(p+6));//越界
return 0;
}⑤数组元素的指针变量
p = &arr[0];取第0个元素地址
p = arr;取数组首地址 等价于第0个元素地址
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5] = {1,2,3,4,5};
int n = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for(i=0;i<n;i++)//遍历数组
{
printf("%d",arr[i]);
}
int *p = arr;
for(i=0;i<n;i++)//遍历数组
{
printf("%d",*(p+i));
}
for(i=0;i<n;i++)//遍历数组
{
printf("%d",*(arr+i));
}
return 0;
}⑥在使用中 [] 就是 *() 的缩写
[]是* ()的缩写 []左边的值放在+的左边 []里面的值 放在+右边 整体取*
arr[6] == *(arr+6)
arr[ 5 ] [ 6 ] == * (arr[5] + 6) ==* ( * (arr + 5 ) + 6)
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5] = {1,2,3,4,5,7,8,9};
int n = sizeof(arr)/sizeof(arr[0]);
printf("%d\n",arr[6]);
printf("%d\n",*(arr+6));
}& arr[0] == & *(arr+0) == arr+0 == arr
⑦扩展
指向同一数组,两指针变量相减 等于他们间的元素个数
int *p1 =arr; int *p2 = arr+4;
p2-p1=4;两指针变量赋值= p2=p1它们指向同一处
两指针变量判断相等 == p2==p1 他们是否相等
两指针变量判断大小 > < >= <= !=
p1>p2 p1!=p2判断位置关系
两指针不能相加(重要)
4、指针数组
指针数组:本质是数组 只是数组的每个元素为 指针。
(1)数值的指针数组
#include <stdio.h>
int main(int argc, char const *argv[])
{
int num1 = 1;
int num2 = 2;
int num3 = 3;
int num4 = 4;
int *arr[5] = {&num1, &num2, &num3, &num4};
int n = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d\n",*arr[i]);
}
return 0;
}(2)字符的指针数组
#include <stdio.h>
int main(int argc, char const *argv[])
{
char *str[] = {"haha","lala","xixi","hehe"};
int n = sizeof(str)/sizeof(str[0]);
int i = 0;
for (i = 0; i < n; i++)
{
printf("%s\n",str[i]);
}
return 0;
}字符串存放在文字常量区,数组内是每个字符串的地址,存放在栈区或全局区
(3)二维字符数组
char *arr1[4]={"hehe", "xixi", "lala", "haha"};
char arr2[4][128]={"hehe", "xixi", "lala", "haha"};arr1是在指针数组 存放的是每个字符串的首元素的地址
arr2是二维字符数组 存放的是每个字符串
5、数组指针
数组指针本质是指针变量保存的是数组的首地址。
(1)数组元素地址 和 数组首地址
数组首元素地址:&arr[0] == arr ,+1跳过一个元素
数组的首地址:&arr ,+1跳过整个数组
数组元素地址与数组首地址相等
(2)int (*p)[5] = NULL; 数组指针
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;访问第3个元素
arr[2] == *(arr+2) == * ( * p+2) == * ( * (p+0)+2) ==*(p[0]+2) ==p [ 0 ] [ 2 ]
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("%d\n",arr[2]);
printf("%d\n",*(arr+2));
printf("%d\n",*(*p+2));
printf("%d\n",*(*(p+0)+2));
printf("%d\n",*(p[0]+2));
printf("%d\n",p [0][2]);
return 0;
}(6)总结
int *arr[5];//指针数组 本质是数组 每个元素为int *
int (*arr)[5];//数组指针 本质是指针变量 保存的是数组的首地址(该数组必须5个元素
每个元素为int)
6、二维数组和数组指针的关系
int arr[5][5] =
{{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15},{16,17,18,19,20},{21,22,23,24,25}};arr既是数组的地址也是数组首元素地址
arr+1表示第二行地址
示例:
arr[1] => *(arr+1) 第一行第0列的列地址
&arr[1] => &*(arr+1)=>arr+1 第1行的行地址
*arr+1 => 第0行第1列的列地址
arr[1]+2 =>*(arr+1)+2 =>第1行第2列的列地址
**arr ==*(*(arr+0)+0) == arr[0][0]案例:访问第19个元素
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5][5] = {{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15}, {16,17,18,19,20},{21,22,23,24,25}};
printf("%d\n",arr[3][4]);
printf("%d\n",*(*(arr+3)+4));
printf("%d\n",*(arr[3]+4));
return 0;
}7、多维数组的物理存储
不管几维数组在物理上 都是一维存储
将二维数组当成一维数组访问
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[5][5] = {{1,2,3,4,5},{6,7.8,9,10},{11,12,13,14,15}, {16,17,18,19,20},{21,22,23,24,25}};
int row = sizeof(arr)/sizeof(arr[0]);
int col = sizeof(arr[0])/sizeof(arr[0][0]);
int *p = &arr[0][0];
int i = 0;
for (i = 0; i < row * col; i++)
{
printf("%d ",p[i]);
}
printf("\n");
return 0;
}8、指针作为函数参数
(1)指针变量作为函数的参数
如果直接将变量的值传递到函数内部修改不能改变变量的值。
int a = 1;
int b = 2;
void my_swap(int x, int y)
{
int tmp = a;
a = b;
b = tmp;
}
my_swap(a,b);//此代码不能交换a,b的值如果想在函数内部修改外部变量的值 需要将外部变量的地址 传递给函数。
#include <stdio.h>
void set_num(int *d)
{
*d=100;
return;
}
int main(int argc, char const *argv[])
{
int num = 0;
set_num(&num);
printf("num = %d\n",num);
return 0;
}(2)数组作为函数的参数
函数内部想操作外部数组元素,将数组名传递给函数。
#include <stdio.h>
void printf_int_array(int *p,int n)
{
printf("sizeof(arr)=%lu\n",sizeof(p));//首元素地址大小8B
printf("arr[2]=%d\n",p[2]);
}
int main(int argc, char const *argv[])
{
int arr[4] = {2,3,4,5};
int n = sizeof(arr)/sizeof(arr[0]);
printf("sizeof(arr)=%lu\n",sizeof(arr));//数组大小4*4B
printf_int_array(arr,n);
return 0;
}案例:键盘输入数组,输出最大值最小值(指针数组作为函数)
#include <stdio.h>
void input_int_array(int *p,int n)
{
printf("请输入%d个int数据:",n);
int i = 0;
for ( i = 0; i < n; i++)
{
scanf("%d",p+i);
}
}
void get_max_min(int *p,int *max_array,int *min_array,int n)
{
int max= p[0],min = p[0];
int i = 0;
for ( i = 0; i < n; i++)
{
if (max < p[i])
{
max = p[i];
}
if (min > p[i])
{
min = p[i];
}
*max_array = max;
*min_array = min;
}
return;
}
int main(int argc, char const *argv[])
{
int arr[5] = {0};
int n = sizeof(arr)/sizeof(arr[0]);
int max=0,min=0;
input_int_array(arr,n);//键盘输入
get_max_min(arr,&max,&min,n);
printf("max=%d \nmin=%d\n",max,min);
return 0;
}(3)二维数组作为函数的参数
函数内部 想操作 函数外部的二维数组 需要将二维数组名 传递给函数。
#include <stdio.h>
void look_array(int (*p)[4],int row,int col)
{
int i=0,j=0;
for ( i = 0; i < row; i++)
{
for ( j = 0; j < col; j++)
{
printf("%d ",p[i][j]);
}
printf("\n");
}
}
int main(int argc, char const *argv[])
{
int arr[3][4] = {{1,2,3,4},{2,5,6,34},{4,8,9,2}};
int row = sizeof(arr)/sizeof(arr[0]);
int col = sizeof(arr[0])/sizeof(arr[0][0]);
look_array(arr,row,col);
return 0;
}(4)函数的返回值类型为指针类型
将函数内部的合法地址 通过返回值 返回给函数外部使用
注意:函数不要返回 普通局部变量的地址
#include <stdio.h>
int* get_add(void)
{
static int data = 10;//静态局部变量,作用于整个进程
return &data;
}
int main(int argc, char const *argv[])
{
int *p;
p = get_add();
printf("%d\n",*p);
return 0;
}(5)函数指针作为指针类型
函数名 代表函数的入口地址;
函数指针:本质是一个指针变量 只是该变量 保存的是函数的入口地址
函数指针p只能保存 有两个int形参以及int返回值 的函数入口地址
int (*p)(int ,int) = NULL;
#include <stdio.h>
int my_add(int x,int y)
{
return x + y;
}
int main(int argc, char const *argv[])
{
int (*p)(int ,int);
p = my_add;
printf("%d\n",p(10,20));
return 0;
}9、总结
数值指针:
int num = 10;
int *p = NULL;p = #
p = #
*p = num;
*p + 1 ==num + 1
一维指针数组:
int arr[4] = {1,6,9,3};
int *p = NULL;
p = arr;p = arr; //数组名等价于元素首地址
p =arr =*(arr+0)= arr[0];
p+1 =arr+1==arr[0]+1;
(p+1) =(arr+1)==arr[1];
arr+1 //第1个元素地址
一维数组指针:
int arr[4] = {12,45,2,78};
int (*p)[4] = NULL;
p = &arr;p = &arr;
p //第0个元素地址,数组首地址
p+1 //跳过整个数组,跳过的地址为数组元素个数*一个数组所占字节
arr //第0个元素地址
arr+1 //第1个元素地址
*(arr+1) //第1个元素
二位指针数组:
int arr[3][4] = {{2,6,3,8},{0,12,6,89},{12,35,98,36}};
int *p = NULL;
p = &arr[0][0];p //首元素地址
p+1 //第1个元素地址
(p+1) //第0行第1个元素(*(p+0)+1)
arr //首元素地址
*arr //首元素地址
*arr+1 //第1个元素地址
(arr+1)//跳到下一行,跳过的地址为第一行元素个数一个元素所占字节
arr+1 //跳到下一行,跳过的地址为第一行元素个数*一个元素所占字节
arr[1] //第1行元素首地址
arr[1]+3 //第1行第3列地址
二位数组指针:
int arr[3][4] = {{2,6,3,8},{0,12,6,89},{12,35,98,36}};
int (*p)[4] = NULL;
p = arr;p , arr //首行地址
p+1 , arr+1 //第1行地址
*p+1 , *arr+1 //第1个元素地址
*(p+1) , *(arr+1) //第1行地址
arr[1] , p[1] //第1行地址
arr[1]+1 , p[1]+1 //第1行第1列地址
*arr[1] , * p[1] //第1行第0列元素
*arr[1]+1 , *p[1]+1 //第1行第0列元素+1
*(arr[1]+1) , *(p[1]+1) //第1行第1列元素
10、如有错误欢迎指正
相关推荐
- SM小分队Girls on Top,女神战队少了f(x)?
-
这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...
- 韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出
-
AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...
- 韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend
-
身高163的Giselle,长腿傲人,身材比例绝了...
- 假唱而被骂爆的女团:IVE、NewJeans、aespa上榜
-
在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...
- 新女团Aespa登时尚大片 四个少女四种style
-
来源:环球网
- 韩国女团aespa新歌MV曝光 画面梦幻造型超美
-
12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...
- 女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA
-
女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...
- 人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?
-
现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...
- 韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞
-
WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...
- aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」
-
记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...
- 南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典
-
女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...
- 章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相
-
搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...
- Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相
-
作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...
- AESPA女团成员柳智敏karina大美女
-
真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...
- 对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了
-
哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...
- 一周热门
- 最近发表
-
- SM小分队Girls on Top,女神战队少了f(x)?
- 韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出
- 韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend
- 假唱而被骂爆的女团:IVE、NewJeans、aespa上榜
- 新女团Aespa登时尚大片 四个少女四种style
- 韩国女团aespa新歌MV曝光 画面梦幻造型超美
- 女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA
- 人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?
- 韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞
- aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」
- 标签列表
-
- filter函数js (37)
- filter函数excel用不了 (73)
- 商城开发 (40)
- 影视网站免费源码最新版 (57)
- 影视资源api接口 (46)
- 网站留言板代码大全 (56)
- java版软件下载 (52)
- java教材电子课本下载 (48)
- 0基础编程从什么开始学 (50)
- java是用来干嘛的 (51)
- it入门应该学什么 (55)
- java线上课程 (55)
- 学java的软件叫什么软件 (38)
- 程序开发软件有哪些 (53)
- 软件培训 (59)
- 机器人编程代码大全 (50)
- 少儿编程教程免费 (45)
- 新代系统编程教学 (61)
- 共创世界编程网站 (38)
- 亲测源码 (36)
- 三角函数积分公式表 (35)
- 函数的表示方法 (34)
- 表格乘法的公式怎么设置 (34)
- sumif函数的例子 (34)
- 图片素材 (36)
