数据结构(C语言指针)

一、指针

1、运算符&

(1)在不同的编译器架构下,&i的大小分别为4字节和8字节,&取出的地址大小是否与int的大小相同与编译器的类型有关系,所以输出变量地址应该采用%p来进行输出,而不是将变量转化为Int类型,然后进行进制转换输出。

scanf("%d",&i);

& 运算符,取得变量的地址,操作数必须为一个变量。

#include<stdio.h>
int main(){
    int i=1;
    printf("0x%x\n",&i);
}

定义一个变量i,使用&取出i的地址,使用16进制进行输出:

查阅相关资料发现:在C语言中输出变量的地址采用%p来进行输出:

#include<stdio.h>
int main(){
    int i=1;
    printf("0x%x\n",&i);
    printf("%p",&i);
}

使用一个变量来接受i的地址:

#include<stdio.h>
int main(){
    int i=1;
    int p;
    p=(int)&i;
    printf("0x%x\n",p);
    printf("0x%x\n",&i);
    printf("%p",&i);
}

当前的编译器选择的是32位架构,结果相同,将编译器改为64位架构:

#include<stdio.h>
int main(){
    int i=1;
    int p;
    p=(int)&i;
    printf("0x%x\n",p);
    printf("0x%x\n",&i);
    printf("%lu\n",sizeof(int));
	printf("%lu\n",sizeof(&i)); 
}

64位架构:

32位架构:

(2)&的操作对象必须为一个变量,如果不是一个变量,那么就无法进行操作。
 

#include<stdio.h>
int main(){
	int a=1,b=2;
	int p;
	p=(int)&(a+b);
	printf("%p",p);
}

(3)相邻变量的地址,变量地址相邻,地址占据4个字节,先定义的变量在地址在后面。

#include<stdio.h>
int main(){
	int a=1,b=2;
	printf("%p\n",&a);
	printf("%p\n",&b);
}

C在16进制为12,12-8=4,4字节刚好与int字节相同,同时ab为本地变量,存储在堆栈里面,堆栈存储变量的方式是从顶向下进行存储。

(4)数组与数组单元的地址:数组名称与第一个数组元素地址及数组地址相同,数组元素地址按从小到大顺序排列。

#include<stdio.h>
int main(){
	int a[10];
	printf("%p\n",&a);
	printf("%p\n",a);
	printf("%p\n",&a[0]);
	printf("%p\n",&a[1]);
	return 0;
}

定义了10个int类型元素的数组,a和&a、a[0]全部相等,而且数组按顺序从大到小排序,间隔4个字节。 

2、指针

知道一个变量的地址,将地址传递给一个函数,是否可以通过地址来访问到变量。

scanf("%d",&a);

scanf也就需要一个东西来存储变量的地址,上述分析将地址交给一个整数随着编译器的变化,其也会发生变化,故C语言引入指针的概念。

(1)一个指针就是一个保存地址的变量。

int i;
int *p=&i;

p是一个指针,将i的地址交给了p(p指向了i)p的值就是i的地址。

(2)定义指针要一个一个的定义。

int *p,q;

上式:q为一个int类型的变量,*p为int类型,p为一个指针。

(3)普通变量的值就是实际的值,指针变量的值就是实际值的地址。

(4)函数应用指针时,应该给传递函数一个地址,外部函数应该使用指针接收,这样外部函数里面的指针就可以访问外面的变量。

void f(int *p){};
int main(){
    int q;
    f(&q);
}
#include<stdio.h>
void f(int *p){
	printf("p=%p\n",p);
}
int main(){
	int a=1;
	printf("&a=%p\n",&a);
	f(&a);
	return 0;
}

通过指针在函数得到了外部变量a的地址, 其与a是有关系的,但是假如直接给函数传入一个a,那么函数就得到了一个数值,其与a并无联系。

(5)p为得到的地址,在C语言中引入单目运算符*来访问得到地址的值,然后进行读写操作。

#include<stdio.h>
void f(int *p){
	int k=*p; 
	printf("*p: %d\n",*p);
	printf("k: %d\n",k);//读变量的值 
	*p=9;//修改变量的值 
}
int main(){
	int a=1;
	printf("a1:%d\n",a); 
	f(&a);
	printf("a2: %d\n",a); 
	return 0;
}

先定义了一个变量a=1,使用地址传入,外部函数使用指针接收,读*p进行读写输出k=1,再进行了*p的修改,返回主函数时,该值修改为9。

int i;
scanf("%d",i);

 不会报错是因为int 为4个字节,用32位编译的时候地址也是4个,scanf会用i的值作为地址去访问,将输入的值写入i那个地址里面,不会报错,但是使用会出错。

3、指针的使用

(1)交换值。

#include<stdio.h>
void f(int *p1,int *p2){
	int t=*p1;
	*p1=*p2;
	*p2=t;
} 
int main(){
	int a=1,b=99;
	printf("交换前:a=%d b=%d\n",a,b);
	f(&a,&b);//交换变量 
	printf("交换后:a=%d b=%d\n",a,b);
	return 0;
}

(2)函数要返回多个值,某些值要指针带回(返回最大最小值)。

#include<stdio.h>
void minmax(int a[],int len,int *min,int *max){
	*min=*max=a[0];
	int i;
	for(i=0;i<len;i++){
		if(a[i]<*min){
			*min=a[i];
		}
		if(a[i]>*max){
			*max=a[i];
		}
	}
}
int main(){
	int a[]={1,23,234,34,12,22,13,341,332,33,4,5};
	int len=sizeof(a)/sizeof(a[0]);
	int min,max;
	minmax(a,len,&min,&max);
	printf("min:%d max:%d",min,max);
	return 0;
}

 (3)返回过程状态

#include<stdio.h>
//除法成功返回1,失败返回0
int cf(int a,int b,int *result){
	int ret=1;
	if(b==0){
		ret=0;
	}else{
		*result=a/b;
	}
	return ret;
}
int main(){
	int a=99,b=2;
	int result;
	if(cf(a,b,&result)){
		printf("成功:%d",result);
	}else{
		printf("失败"); 
	}
	
} 

tips: 

int *p;
*p=12;

*p随机指向一个地址,当赋值的时候,如果该地址的值可以修改,那么代码不会出错,但是不可修改,那么代码就会崩溃。

4、指针与数组

#include<stdio.h>
void minmax(int a[],int len,int *min,int *max){
	*min=*max=a[0];
	int i;
	printf("minmaxsizeof:%lu\n",sizeof(a));
	printf("minmax :%p\n",a);
	for(i=0;i<len;i++){
		if(a[i]<*min){
			*min=a[i];
		}
		if(a[i]>*max){
			*max=a[i];
		}
	}
}
int main(){
	int a[]={1,23,234,34,12,22,13,341,332,33,4,5};
	printf("mainsizeof:%lu\n",sizeof(a));
	printf("main :%p\n",a);
	int len=sizeof(a)/sizeof(a[0]);
	int min,max;
	minmax(a,len,&min,&max);
//	printf("min:%d max:%d",min,max);
	return 0;
}

发现传入的数组实际上为一个指针,sizeof(a)=sizeof(*int),将传入参数修改为指针:

#include<stdio.h>
void minmax(int *a,int len,int *min,int *max){
	*min=*max=a[0];
	int i;
	printf("minmaxsizeof:%lu\n",sizeof(a));
	printf("minmax :%p\n",a);
	for(i=0;i<len;i++){
		if(a[i]<*min){
			*min=a[i];
		}
		if(a[i]>*max){
			*max=a[i];
		}
	}
}
int main(){
	int a[]={1,23,234,34,12,22,13,341,332,33,4,5};
	printf("mainsizeof:%lu\n",sizeof(a));
	printf("main :%p\n",a);
	int len=sizeof(a)/sizeof(a[0]);
	int min,max;
	minmax(a,len,&min,&max);
//	printf("min:%d max:%d",min,max);
	return 0;
}

结果相同,在过程里面可以进行[]运算,[]与*在原型上面是等价的。

数组变量是特殊的指针,数组变量本身表示为地址,无须使用&;但是数组单元表示的是变量,需要使用&。

int arr[10];
int *p=arr;

[]除了可以对数组进行使用还可以对指针进行使用,*不仅可以对指针进行使用还可以对数组进行使用。

#include<stdio.h>
int main(){
	int arr[10]={11,2,3,4,34,35,6,4,657,23};
	int *p=arr;
	printf("p[0]:%d\n",p[0]);//第一个元素 
	printf("p[1]:%d\n",p[1]);//第一个元素 
	printf("*arr:%d\n",*arr);
	return 0;
} 

数组变量本身为一个const指针,所以对数组变量不可以进行直接赋值。 

int a[]  --> int * const a

指针与const关系:

int * const p=&a;
*p=100;
p++;

const指针表示p的值不可以改变,p为a的地址,但是*p是可以进行修改的。

const int *p=&a;
*p=100;
a=200;
p=&j;

上述不可以,因为const让*p不可以修改,其它均可以修改,可以修改p所指的对象,以及其它操作。

二、指针的运算

#include<stdio.h>
int main(){
	char a[]={0,1,2,3,4,5,6,7,8,9,};
	char *p=a;
	printf("p:   %p\n",p);
	printf("p+1: %p\n",p+1);
	int b[]={0,1,2,3,4,5,6,7,8,9,};
	int *q=b;
	printf("q:   %p\n",q);
	printf("q+1: %p\n",q+1);	 
	return 0;
} 

对指针加1其对应的是在地址上加上sizeof(值) ,也就对指针加1,指针指向下一个单位元。

#include<stdio.h>
int main(){
	char a[]={0,1,2,3,4,5,6,7,8,9,};
	char *p=a;
	printf("*(p+1): %d\n",*(p+1));
	int b[]={0,1,2,3,4,5,6,7,8,9,};
	int *q=b;
	printf("*(q+1): %d\n",*(q+1));	 
	return 0;
} 

指向下一个单位元,1+1!=2 !!!下式等价。

*(p+i)=a[i];
*(q+i)=b[i];

 两个指针相减,返回的是地址相减/对应的sizeof(值):

#include<stdio.h>
int main(){
	char a[]={0,1,2,3,4,5,6,7,8,9,};
	char *p=a;
	char *p1=&a[5];
	printf("p1-p:%d\n",p1-p);
	int b[]={0,1,2,3,4,5,6,7,8,9,};
	int *q=b;
	int *q1=&b[5];
	printf("q1-q:%d\n",q1-q); 
	return 0;
} 

*p++遍历数组:

*p++:取出*p的值,随便将指针移向后一位:

#include<stdio.h>
int main(){
	char a[]={0,1,2,3,4,5,6,7,8,9,-1};
	char *p=a;
	int i; 
	for(i=0;i<sizeof(a)/sizeof(a[0]);i++){
		printf("%d\n",a[i]);//for循环遍历数组 
	}
	while(*p!=-1){//条件可以在最后加一个值进行判断 
		printf("%d\n",*p++);//while循环指针遍历 
	} 
	return 0;
} 

0地址:每个程序都有一个零地址,但是不可以触碰,C语言采用null表示0地址,可以使用其进行指针初始化,看指针是否有用。

不同类型的指针不可以相互赋值。

void* :不知道指向什么东西的指针。

指针用处:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值