前言:
而今大家对“指针取地址和取值”可能比较看重,小伙伴们都需要分析一些“指针取地址和取值”的相关资讯。那么小编在网上汇集了一些对于“指针取地址和取值””的相关资讯,希望朋友们能喜欢,你们一起来学习一下吧!概述
系统为内存的每一个字节 分配一个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、如有错误欢迎指正
标签: #指针取地址和取值