C语言(指针、数组 、 const、动态内存分配 )——详解

指针 :

指针也就是内存地址,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的存储空间长度也不同。有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。 —— 百度百科

#include<stdio.h>

void f(int *); 

int main()
{
	int i=1;
	int a=2;
	int *p=&i;
	/*
		表示int是一个指针,它指向一个int,现在把i的地址交给了p
		它同等于:
		int *p;
		p=&i;
		但注意的是,不能像下面这样写:
		int *p;
		*p=&i;
		这样的用法是不对的。
	*/
	p=&i; //&符号的作用:取地址,是个取地址符(注意C语言没有引用,C++才有引用)
	printf("p的值   %p\n",p);
	printf("&i      %p\n",&i);
	/*
		可以从下面的输出结果看到,p的值和i的地址是一样的,可见
	在指针变量p里面放的是地址,而不是实际的值,从而说p是指向变
	量i的一个指针(p指向了i)。
	*/
	printf("p=&i    %d\n",*p);
	*p=a;
	/*
	*是一个单目运算符,用来访问指针的值所表示的地址上的变量,
	*p可以做右值也可以做左值。p的值是a的地址,*p代表了a。
	所以可以通过*p来改变*p所指向的变量的值。在输出结果中所示,
	因为p是指向i的指针,经过*p=a结果f(&i)输出结果为2。
	*/
	printf("*p=a    %d\n",*p);
	f(&i);//指针做参数时传地址
	return 0;
} 

void f(int *p_)
{	
	printf("f(&i)   %d\n",*p_);
}

运行结果:
在这里插入图片描述

左值之所以叫左值: 是因为出现在赋值号左边的不是变量,而是值,是表达式计算的结果。
a[0] = 2; * p = 3;
*是个运算符,*p代表去取得p这个指针它的地址所代表的那个变量。
数组的方括号[ ]也是一个运算符,是取下标的运算符。

如果对取得的地址去取它所代表的变量,那就是原来的那个变量
如果对一个指针所指的那个变量再去取地址那就是原来那个指针

void swap(int *m,int *n)//函数可以通过指针返回多个值
{
	int tmp;
	tmp=*m;
	*m=*n;
	*n=tmp;
}

数组与指针 :

数组变量本身表达地址
int a[10]; int *p=a;
无需用& 取地址 但是数组的单元表达的是变量,需要用&取地址 a==&a[0];
[ ]运算符可以对数组做,也可以对指针做。 p[0] <==> a[0] *运算符可以对指针做,也可以对数组做

数组变量是const的指针,所以不能被赋值 int a[ ] <==> int * const a=…

#include<stdio.h>

void minmax(int a[],int len,int *max,int *min);
// void minmax(int *a,int len,int *max,int *min);

int main()
{
	int a[]={1,2,3,4,5};
	int min,max;
	printf("main sizeof(a)=%lu\n",sizeof(a));
	minmax(a,sizeof(a)/sizeof(a[0]),&min,&max);//a==&a[0]
	printf("min=%d,max=%d\n",min,max);
	printf("a[0]的地址  %p\n",&a[0]);
	//数组的单元表达式是变量,需要用&取地址
	printf("a的地址     %p\n",a);
	//从下面的输出可知,a本身表达地址 
	// a==&a[0];
	return 0;
} 
 
 void minmax(int a[],int len,int *min,int *max)
 //void minmax(int *a,int len,int *min,int *max)
 // a[]其实是个指针,等同于*a,所以可以换成*a
{
	int i;
	printf("minmax sizeof(a)=%lu\n",sizeof(a));
	*min = *max = a[0];
	for (int i=0;i<len;i++){
		if(a[i]<*min){
			*min = a[i];
		}
		if(a[i]>*max){
			*max=a[i];
		}
	}
}
/*
函数参数表中的数组实际上是指针
sizeof(a)==sizeof(int *)
但是可以用数组的运算符进行运算
*/ 

输出结果(32位架构):
在这里插入图片描述

以下四种函数原型是等价的 :

int sum (int *ar,int n);
int sum (int *,int);
int sum (int ar[],int n);
int sum (int [],int);

数组变量是const指针:

#include<stdio.h>
int main(){
	int a[]={1,2,3,4,5};
	int b[10];
	b=a;//这样是不行的!!!
	/*
	数组变量间是不能赋值的
	int a[] 可以看作是 int * const a;
	所以数组变量是个常量,被初始化出来了就不能变了,
	所以数组是一个常量指针
	*/
	return 0;
}
指针与const :

如果const在 * 号的前面,表示指针所指向的地址不能被修改。如果在后面,则表示不能通过指针去修改它指的变量的值。

int *const p = &i;//p永远指向i的地址,它们的关系永远不变
*q = 12;//OK
q++;//ERROR
 


//int const *p = &i;
const int *p = &i;//表示不能通过指针p去修改那个变量。
 *p = 12;//ERROR  ( *p 是const )
 i=12;//OK
 p=&j;//OK
 
数组与const :

const int a[]={1,2,3};

  • 表示数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int
  • 所以必须通过初始化进行赋值
#include<stdio.h>
int main(){
	const int a[]={1,2,3};//必须这样赋值
	//等同于 int const a[]={1,2,3};
	//const int a[3];//ERROR
	
	a[0]=12; //ERROR
	return 0;
} 
int sum (const int a[])
//可以保护数组不被在函数里面修改值,也就是说函数里没有办法去修改数组的值
例如:

#include<stdio.h>

int sum (const int a[])
{
	a[0]=12;//ERROR: 函数内部不能修改数组
	return a[0];
}
	
int main()
{	
	int a[]={1,2,3};//注意这里没有用const
	return 0;
} 
指针的相关运算 :

指针的运算: 当取两个指针的减法时得到的是这两个地址的差除以sizeof(类型); 指针的比较:

  • <,<=,==,>,>=,!= 都可以对指针做
  • 比较它们在内存中的地址
  • 数组中的单元的地址肯定是线性递增的 0地址:
  • 内存中有0地址,但是0地址通常是个不能随便碰的地址
  • 所以指针不应该有0值
  • 因此可以用0地址来表示特殊的事情: * 返回的指针是无效的 * 指针没有被真正初始化(先初始化为0)
  • NULL是一个约定定义的符号,表示0地址 * 有的编译器不愿意你用0来表示0地址

指针的类型转换:

  • void*表示不知道指向什么东西的指针
    • 计算时与char*相同(但不相通)
  • 指针也可以转换类型
    • int *p=&i; void *q=(void *)p ;
      *这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量
    • 我不当你int,我认为你就是个void
#include<stdio.h>
int main(){
	char ac[]={0,1,2,3,4,5,6,7,8,9,-1};
	char *p=ac;
	char *p1=&ac[5];
	printf("p    = %p\n",p);
	printf("p1   = %p\n",p1);
	printf("p+1  = %p\n",p+1);
	/*
	p+1就是在p的地址上加sizeof(char);
	所以下面的q+1就是p的地址+sizeof(int);
	如果指针指的不是连续的内存空间,那么这种运算显然没有意义
	*/
	printf("p1-p = %d\n",p1-p);
	/*
	得到的是两个p1和p的地址的差再除以sizeof(char);
	下面的q1-q同理
	*/
	printf("*(p+2) = %d\n",*(p+2));
	/*
	从下面的输出结果可知*(p+2)等同于ac[2]
	*/
	putchar('\n');
	int ai[]={0,1,2,3,4,5,6,7,8,9};
	int *q=ai;
	int *q1=&ai[5];
	printf("q    = %p\n",q);
	printf("q1   = %p\n",q1);
	printf("q+1  = %p\n",q+1);
	printf("q1-q = %d\n",q1-q);
	printf("*(q+2) = %d\n",*(q1+2));
	putchar('\n');
	printf("sizeof(char) = %d\n",sizeof(char));
	printf("sizeof(int ) = %d\n",sizeof(int));
	putchar('\n');
	while(*p!=-1){
		printf("%d ",*p++);
	}
	/*
	取出p所指的那个数据来,完事之后顺便把p移到下一个位置去
	*的优先级高,但是没有++高
	常用于数组类的连续空间操作
	在某些CPU上,这可以直接被翻译成一条汇编命令
	*/
	
	//q=p; ERROR 两个不同类型的值针不能相互赋值
	return 0; 
} 

输出结果(32位架构):
在这里插入图片描述

动态内存分配:
#include<stdio.h>
#include<stdlib.h>//malloc的头文件
int main(){
	int number;
	int *a;
	scanf("%d",&number);
	a=(int*)malloc(number*sizeof(int));
	/*
	向malloc申请的空间的大小是以字节为单位的
	之所以要用(int*) 强制类型转换,是因为malloc返回的是void*类型的,需要转换为我们需要的类型
	*/
	free(a);
	/*
	申请得来的空间需要要(还回去)释放
	*/
	a++;
	free(a);//ERROR 
	/*
	只能还申请来的空间的首地址
	int i;
	a=&i;
	free(a);//ERROR
	
	free是malloc配套的函数,申请的空间需要还回去
	*/
	return 0;
}

参考资料:
https://baike.baidu.com/item/%E6%8C%87%E9%92%88/2878304?fr=aladdin
https://www.icourse163.org/?from=study(C语言 — 翁恺老师)
http://www.imooc.com/article/30475

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值