关于指针分析

发布于:2022-12-25 ⋅ 阅读:(175) ⋅ 点赞:(0)

目录

1概念

2指针的相关操作

3指针和变量的关系

4指针变量的运算

5指针和一维数组

6指针和二维数组

7数组指针

8指针数组

9指针和字符串

10二级指针

11const关键字


1概念

        内存中每个字节的空间都有一个编号,这个编号叫做地址,也叫做指针,也就是说,指针变量就是地址编号;保存指针的变量称之为指针变量。

平时使用中:地址编号:地址 保存地址的变量:指针

2指针的相关操作

        & 获取变量的地址

        * 在定义变量时加上*,只起到标识作用,标识定义的变量是一个指针变量

        其他场景遇到*表示操作地址中的内容

3指针和变量的关系

        p中保存了a的地址,也就是0x20

        通过p可以操作0x20地址里的内容

        *p = 100; //表示将0x20地址开始的4个字节(因为p是int类型的指针)的空间置成100

        //等价于 a = 100;

//内存中每个字节的空间都有自己的编号,这个编号就是地址
//当程序运行到定义变量时,会根据变量的类型,给变量分配合适大小的空间用来保存数据。

int a = 10;

//可以通过 &变量名 获取变量的地址,变量的地址一般用指针变量保存
//存储类型 &变量名 *指针变量名;

// %p 输出地址的

int *p = &a;	//用a的地址初始化指针变量p
printf("&a = &p		p = %p\n",&a,p);

int *p2 = &100;	//错误,常量没有地址可言

//可以通过p修改a的值
*p = 20;	//等价于a = 20;
printf("a = %d	*p = %d\n",a,*P);

//一般不使用普通变量保存地址,因为无法进行 *p变量名 的操作
//long int temp = &a;	//警告
//printf("temp = %#lx\n",temp);
//*temp = 30;	//错误

#if 0
a = 0x12345678;
cahr *p3 = &a;
printf("&a = &p		p3 = %p\n",&a,p3);
//指针能访问几个字节,取决于定义时给定的类型,与指针保存地址的变量的类型无关
printf("&a = %#x	*p3 = %#x\n",a,*p3);//a = 0x12345678	*p3 = 0x78
#endif

//指针变量自身也需要占用空间来存储地址数据
//64位系统:指针变量占8个字节	32位系统:指针变量占4个字节

cahr *t1;	//short、int、float、long
printf("sizeof(t1) = %ld\n",sizeof(t1));

//指针变量本质也是一个变量,也需要分配空间保存数据
printf("&t1 = %p\n",&t1);

4指针变量的运算

        指针变量中保存的地址的相关运算

        地址只能进行如下运算:+ - ++ -- > < >= <= == != =

        注意:相同类型的指针之间做运算才有意义。

int s[5] = {10,20,30,40,50};

int *p1 = &s[0];
int *p2 = &s[3];
//两个指针做差得到的是相差的数据类型的个数
//数据类型指的是:定义指针时的类型
printf("p2-p1 = %ld\n",p2-p1);	//3

char *p3 = (char *)&s[0];
char *p4 = (char *)&s[3];
printf("p4-p3 = %ld\n",p4-p3);	//12

int *p5 = &s[0];
printf("p5 = %p	*p5 = %d\n",p5,*p5);

int *p6 = p5+1;	//指针+1 是加了一个数据类型(定义指针时的类型),并不是地址数据+1
printf("p6 = %p	*p6 = %d\n",p6,*p6);

//指针变量可以被赋值(改变指向)
int a = 10;
int *q = &a;
int b = 20;
q = &b;//改变的是值,如果是*q = &b;则改变的是地址

5指针和一维数组

int s[6] = {10,20,30,40,50,60};
printf("s[0] = %d\n",s[0]);
printf("s[3] = %d\n",s[3]);

//数组名是一个地址常量,保存的时数组的首地址
//通过 数组名[下标] 的方式访问数组成员
//本质上以数组名存的地址为基准,偏移几个数据元素,然后取值的操作
printf("s = %p	*s = %d\n",s,*s);
printf("s+3 = %p	*(s+3) = %d\n",s+3,*(s+3);

int *p = s;	//可以将数组名的地址赋值给指针变量      
int *p2 =&s[0];
//int  *p = &s;
//&数组名 数组名 &s[0] 	这三个地址的值是一样的,但 &数组名 会有警告(不使用)	
       
//当指针变量保存了数组的首地址后
s[i] == *(s+i) == *(p+i) == p[i]

       
//一维数组的遍历
int i = 0;
for(i=0;i<6;i++){
    //printf("%d  ",s[i]);
    //printf("%d  ",*(s+i));
    //printf("%d  ",p[i]);
    printf("%d  ",*(p+i));
}
       
p++;	//p是指针变量,可以被赋值 p = p+1
//s++;	//错误,s是地址常量,不可以被赋值

        用指针实现strcpy功能

#include <stdio.h>
int main(int argc,const char*argv[]){
	char dest[64] = "abcd";
	cahr src[] = "www.hqyj.com";
	
	cahr *p = dest;
	cahr *q = src;
	
	while(*q != '\0'){
		*p++ = *q++;
	}
	*p = *q;	//将最后的 \0 也复制过来
	
	p = dest;	//需要将p重新指向dest的首地址
	printf("%s\n",p);
	
	return 0;
}

6指针和二维数组

int s[3][4] = {{1,2,3,4},
			   {5,6,7,8},
			   {9,10,11,12}};

//二维数组的数组名也是一个地址常量,是一个行指针,每次 +1 偏移的是一行数据元素
printf("s = %p	s+1 = %p\n",s,s+1);	//相差16

//*s 对二维数组的数组名取*,相当于对行指针进行降维,将为列指针
printf("*s = %p	*s+1 = %p\n",*s,*s+1);	//相差16

//如果想取到二维数组中的数据,需要加两个*
//s[i] == *(s+i)
//s[i][j] == *(*(s+i)+j)
printf("%d\n",**s);	//1
printf("%d\n",*(*s+1));	//2
printf("%d\n",*(*(s+1)));	//5
printf("%d\n",*(*(s+1)+1));	//6
printf("%d\n",*(*(s+2)+3));	//12

//由于二维数组的数组名是一个行指针,每次+1是偏移一行,所以不能使用普通的指针去保存二维数组数组名的地址
int *p = s;	//警告,一维数组可以,但二维数组不可以
//p+1是偏移一个int,s+1是偏移一行
 //二维数组的遍历
int i = 0;
int j = 0
for(i=0;i<3;i++){
	for(j=0;j<4;j++){
	//printf("%d  ",s[i][j]);
	printf("%d  ",*(*(s+i)+j));
	}
	printf("\n");
}

7数组指针

        本质是一个指针,指向一个数组(二维数组) ​ 也称之为 行指针

        格式:数据类型 (*数组指针名)[列数];

int s[3][4] = {{1,2,3,4},
			   {5,6,7,8},
			   {9,10,11,12}};
	//多用于二维数组的传参
	int (*p)[4] = s;
	printf("p+1 = %p	s+1 = %p\n",p+1,s+1);	//地址是一样的
	
//s[i][j] == *(*(s+i)+j) == p[i][j] ==*(*(p+i)+j)

int i = 0;
int j = 0
for(i=0;i<3;i++){
	for(j=0;j<4;j++){
	//printf("%d  ",s[i][j]);
	//printf("%d  ",*(*(s+i)+j));
	//printf("%d  ",p[i][j]);
	}
	printf("\n");
}
p++;	 //p是变量,s是常量
//s++;	//报错


//关于一维数组名取地址
int s[5]= {1,2,3,4,5};
//&s:相当于给s这个列支指针升维成行指针,编译器会理解成你的 p+1 偏移一整行,但p值偏移一个int		所以int *p = &s;没人用
//可以使用数组指针消除警告,但指针就不能偏移了,偏移越界
int (*p)[5] = &s;
printf("%d\n",*(p+1));//越界

8指针数组

        本质是一个数组数组中的每一个成员都是一个指针

        格式:数据类型 *数组指针名[数组长度];

//可以用二维数组保存多个字符串,可能会出现空间上的严重浪费
char s[4][64] = {"liu","wang","wei","asdasdasfa.asdsafasfa.aa"};
int i = 0;
for(i = 0;i<4;i++){
	printf("%s\n",s[i]);
}
printf("sizeof(s) = %ld\n",sizeof(s));	//4*64*1(数据类型) = 256

//定义指针数组,指向字符串
char *p[4];	//定义一个长度为4的数组,数组的每一个元素都是一个char*
//p是数组名
printf("sizeof(p) = %ld\n",sizeof(p));	//4*8 = 32
char name1[] = "liu";
char name2[] = "wang";
char name3[] = "wei";
char name4[] = "asdasdasfa.asdsafasfa.aa";
p[0] = name1;
p[1] = name2;
p[2] = name3;
p[3] = name4;
for(i = 0;i<4;i++){
	printf("%s\n",p[i]);
}


//初始化方式
char *p2[4] = {"hello","world","beijing","nihao"};
for(i = 0;i<4;i++){
	printf("%s\n",p2[i]);
}

printf("%c\n",p2[1][1]);	//取world的o

9指针和字符串

//定义一个字符数组,保存字符串
char str[] = "hello";
printf("%s\n",str);
//字符数组保存在字符串的栈区上,可以修改
str[1] = 'E';

//操作系统不会将相同的地址空间同时分配给两个变量
char str2[] = "hello";

//用一个char *类型的指针指向一个字符串
//指针指向的字符串是一个 字符串常量 在常量区不可以修改
cahr *p = “world”;
printf("%s\n",p);
p[1] = '0';	//编译不报错,执行段错误

//不管有多少个指针,只要指向同一个字符串常量,那保存的地址就是相同的
cahr *p2 = “world”;

//内存
//栈区(int a; int*p系统自动分配,自动回收)和堆区(程序员自己分配,自己释放)都可以修改,但是静态区(100,abc常量)不可以修改

10二级指针

//二级指针多用于一级指针传参----数据结构经常用
int a = 10;
int *p &a;
int **q = &p;//定义二级指针保存一级指针的地址

//a == *p == **q ==10	取值
//&a == p == *q		取地址
printf("a == %d	*p = %d	**q = %d\n",a,*p,**q);
printf("&a = %p	p = %p	*q = %p\n",&a,p,*q);

//可以用一级指针保存一级指针的地址,只能保存,不能取**操作
int *p1 = &p;
printf("p1 = %p	q = %p\n",p1,q);	//地址是相同的
printf("%d\n",**p1);	//错误

11const关键字

        const是C语言的一个关键字,用来修饰变量,表示只读

int a = 10;a = 20;

const  int b; b = 20;	//错误,b的值是只读
//const修饰的a是只读的,对于只读变量 潜规则要求必须初始化,否则就是随机值且不能修改
const int a = 10;
//a = 20;	//错误,不可以修改

//const修饰指针
int m = 10;
int n = 20;

//const 修饰的是*p,表示不能通过 指针p1 修改m的值
const int *p1 = &m;
*p1 = 50;	//错误,不能通过*p修改
m = 50;	//但是可以通过m修改,因为m没有const修饰

//和上面一样
int const *p2 = &m;

//const修饰的是p,表示p不能改 指针不能改变指向
int *const p3 = &m;
//*P3 = 100;	//允许
//p3 = &n;	//错误

//指针的指向不能修改,也不能通过指针修改指向内容
const int *const p4 = &m;


网站公告

今日签到

点亮在社区的每一天
去签到