指针--C语言最重要和最复杂概念之一的重新理解-创新互联

声明:本文参照了C primer Plus中文版、翁凯C语言课程数组和指针章节

公司专注于为企业提供成都网站设计、网站建设、微信公众号开发、电子商务商城网站建设小程序开发,软件按需网站策划等一站式互联网企业服务。凭借多年丰富的经验,我们会仔细了解各客户的需求而做出多方面的分析、设计、整合,为客户设计出具风格及创意性的商业解决方案,成都创新互联公司更提供一系列网站制作和网站推广的服务。

目录

指针概念

访问地址变量*

两数交换

找到数组中的大值和最小值

指针最常见的错误

指针与数组

数组变量是特殊的指针

指针运算

*p++

指针类型


指针概念
  • 指针:用于存储变量地址。从根本上来看,指针是一个值为内存地址的变量(或数据类型)。正如char类型变量的值是字符,int类型变量的值是整数。

作为参数的指针:

  • void f(int *p)
  • 在被调用的时候得到某个变量的地址;
  • int i=0; f(&i);
  • 在函数里面可以通过这个指针来访问外面的i。

下面看一个例子:

#includevoid f(int *p);

int main(){
	int i=6;
	printf("&i=%p\n",&i);
	f(&i);
	return 0;
} 

void f(int *p){
	printf(" p=%p\n",p);
}

从运行结果可以知道,i的地址是000000000062FE1C,通过f函数将地址取出来然后赋给了p指针,于是可以说p是一个指向i变量的指针。

访问地址变量*
  • *是一个单目运算符,用来访问指针的值所表示的地址上的变量
  • 可以做右值也可以做左值,比如:int k= *p;  *p=k+1; 
#includevoid f(int *p);
void g(int k);

int main(){
	int i=6;
	printf("&i=%p\n",&i);
	f(&i);
	g(i);
	
	return 0;
} 

void f(int *p){
	printf(" p=%p\n",p);
	printf("*p=%d\n",*p);
}

void g(int k){
	printf("k=%d\n",k);
}

void f(int *p){
	printf(" p=%p\n",p);
	printf("*p=%d\n",*p);
	*p=26;
}

传进来的是i的地址,对*p进行修改实际上是对i的值进行修改,p是i的地址,*p用来访问p指针所代表的值。

两数交换
#includevoid swap2(int a,int b);
int main(){
	int a=5,b=6;
	swap2(a,b);
	printf("a=%d,b=%d\n",a,b);
	
	return 0;
}
void swap2(int a,int b){
	int t = a;
	a = b;
	b = t;
}

先分析一下这个程序能够交换a,b两数的值吗?很明显是不能交换成功的,我们只是在swap中重新定义了两个值a和b,这里的a和b地址和主函数中的地址是不一样的,对其进行交换的话也不能改变主函数中a和b的地址,地址不变的话,其值更不会改变。 

#includevoid swap(int *pa,int *pb);
void swap2(int a,int b);
int main(){
	int a=5,b=6;
	swap2(a,b);
	printf("a=%d,b=%d\n",a,b);
	swap(&a,&b);	
	printf("a=%d,b=%d\n",a,b);
	return 0;
}

void swap(int *pa,int *pb){
	int t = *pa;
	*pa = *pb;
	*pb = t;
}

void swap2(int a,int b){
	int t = a;
	a = b;
	b = t;
}

所以需要在函数中对其做到修改需要对地址进行修改。

找到数组中的大值和最小值
#includevoid minmax(int a[],int len,int *max,int *min);

int main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int min,max;
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
	printf("min=%d,max=%d\n",min,max);
	
	return 0; 
}

void minmax(int a[],int len,int *min,int *max){
	int i;
	*min = *max = a[0];
	for(i=1;i*max){
			*max=a[i];
		}
	}
}

指针最常见的错误

定义了指针变量,还未指向任何变量就直接开始使用。

p指向的地址可能恰好是不能赋值的地方,这时候可能就会报错。

指针与数组

在不同的系统中,C语言指针的大小是不同的。
在32位系统(即x86)中,指针的大小为4字节。
在64位系统(即x64)中,指针的大小为8字节。

#includevoid minmax(int a[],int len,int *max,int *min);

int main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int min,max;
	printf("main sizeof(a)=%lu\n",sizeof(a));
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
	printf("min=%d,max=%d\n",min,max);
	
	return 0; 
}

void minmax(int a[],int len,int *min,int *max){
	int i;
	printf("minmax sizeof(a)=%lu\n",sizeof(a));
	*min = *max = a[0];
	for(i=1;i*max){
			*max=a[i];
		}
	}
}

可以看到在minmax中a的大小恰好等于一个指针的大小,

#includevoid minmax(int a[],int len,int *max,int *min);

int main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int min,max;
	printf("main sizeof(a)=%lu\n",sizeof(a));
	printf("main   a=%p\n",a);
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
	printf("min=%d,max=%d\n",min,max);

	return 0; 
}

void minmax(int a[],int len,int *min,int *max){
	int i;
	printf("minmax sizeof(a)=%lu\n",sizeof(a));
	printf("minmax a=%p\n",a);
	*min = *max = a[0];
	for(i=1;i*max){
			*max=a[i];
		}
	}
}

#includevoid minmax(int a[],int len,int *max,int *min);

int main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int min,max;
	printf("main sizeof(a)=%lu\n",sizeof(a));
	printf("main   a=%p\n",a);
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
	printf("min=%d,max=%d\n",min,max);

	return 0; 
}

void minmax(int a[],int len,int *min,int *max){
	int i;
	printf("minmax sizeof(a)=%lu\n",sizeof(a));
	printf("minmax a=%p\n",a);
	a[0]=1000;
	*min = *max = a[0];
	for(i=1;i*max){
			*max=a[i];
		}
	}
}

在maxmin中将a[0]改写成1000,这个发现大值最小值都发生了变化,此时最小值为2,大值为1000,那么1000是怎么来的呢,很明显是刚刚修改a数组后得到的。这时候也说明了函数参数中a[]表示的是一个指针。

既然是一个指针,那么写成指针的形式肯定也没有什么区别,将a[]修改成*a再进行编译,发现没有区别。

#includevoid minmax(int *a,int len,int *max,int *min);

int main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int min,max;
	printf("main sizeof(a)=%lu\n",sizeof(a));
	printf("main   a=%p\n",a);
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);
	printf("min=%d,max=%d\n",min,max);

	return 0; 
}

void minmax(int *a,int len,int *min,int *max){
	int i;
	printf("minmax sizeof(a)=%lu\n",sizeof(a));
	printf("minmax a=%p\n",a);
	a[0]=1000;
	*min = *max = a[0];
	for(i=1;i*max){
			*max=a[i];
		}
	}
}

  • 函数参数表中的数组实际上是指针 sizeof(a)== sizeof(int *)
数组变量是特殊的指针

数组变量本身表达地址,所以

  • int a[10];int *p=a;//无需使用&取地址
  • 但是数组的单元表达的是变量,需要用&取地址
  • a=&a[0]

[ ]运算符可以对数组做,也可以对指针做:

  • p[0] <==>a[0]

*运算符可以对指针做,也可以对数组做:

  • *a=1;

数组变量是const指针,所以不能被赋值

  • int a[]<==>int * const a   不能再赋值
#includeint main(){
	int a[] = {1,2,3,4,5,6,7,8,9,12,13,14,16,17,47,24,55,89};
	int *p = a;
	printf("*p=%d\n",*p);
    printf("p[0]=%d\n",p[0]);
	printf("p[5]=%d\n",p[5]);
	return 0; 
}

对着个代码运行的结果可以这样理解:p指针指向的是数组a,p[0]是指将所指的地方当做一个数组,取该数组的第1个元素,p[5]表示取数组a的第6个元素。

指针运算
#includeint main(){
	char ac[] = {0,1,2,3,4,5,6,7,8,9};
	char *p = ac;
	printf("p  =%p \n",p);
	printf("p+1=%p \n",p+1);
	
	int ai[] = {0,1,2,3,4,5,6,7,8,9};
	int *q = ai;
	printf("q  =%p \n",q);
	printf("q+1=%p \n",q+1);
	return 0;
}

地址变化:sizeof(char)=1,sizeof(int)=4.当我们给一个指针+1的时候,我们的地址变化并不是在地址值上+1,而是在地址值上加一个sizeof(数据类型)。 

这些算术运算可以对指针做:

  • 给指针加、减一个整数(+, +=,-,-=)
  • 递增递减(++/- -)
  • 两个指针相减

两个指针相减的结果是什么?通过以下程序可以很清楚的了解到。

这里也并不是直接的通过地址值相减,而是减完后除以了sizeof(数据类型),得到的是这两个指针之间有多少个这样的地址,或者能放几个这样的地址。

*p++
  • 取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
  • *p的优先级虽然高,但是没有++高
  • 常用于数组类的连续空间操作
  • 在某些CPU上,这可以直接被翻译成一 条汇编指令

指针类型
  • 无论指向什么类型,所有的指针的大小都是一样的,因为都是地址
  • 但是指向不同类型的指针是不能直接互相赋值的
  • 这是为了避免用错指针

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


本文标题:指针--C语言最重要和最复杂概念之一的重新理解-创新互联
浏览地址:http://myzitong.com/article/djjpij.html