欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C语言----指针(一)

程序员文章站 2024-03-07 15:32:51
...

在计算机的内存存储器中,拥有大量的存储单元。一般情况下,存储单元是以字节为单位进行管理的。为了区别内存中的每一个字节,就需要对每一个内存单元进行编号,且每个存储单元都有一个唯一的编号,这个编号就是存储单元的地址,称为内存地址。这样,当需要存放数据时,即可在地址所标识的存储单元中存放数据。当需要读取数据时,根据内存单元的编号或地址即可找到所需的内存单元。

根据内存地址就可以准确定位到对应的内存单元,因此内存地址通常也称为指针。

对一个内存单元来说,内存单元的地址即为指针,内存单元中存放的数据就是该内存单元的内容。

指针==地址

一、指针的定义

int *p;                 //定义一个整型指针变量p  

取地址符 &  如:&a(得到a的地址)

int x = 10;          //整型变量存放整型值

int *p = &a;       //整型地址(指针)变量存放整型地址

int a;
int *p = &a;  //定义一个整型指针变量p存放a的地址 
*p = 100; //即a = 100; *p间接访问符,解引用

“*”所代表的意义如下:

(1)代表双目运算符里的乘法

(2)前面有数据类型(如int等),有进行定义。所指的是指针变量 

(3)前面无数据类型,间接访问,代表解引用

指针变量比普通变量多了一个解引用。使用指针时,须要解引用才能使用。

printf("%d\n",sizeof(char *));    //这里的char是所有数据类型的一个例子

output: 4

说明:只要是输出指针,所输出的字节数都为4(在32位平台时输出4,在64位平台时输出为8)  可检测平台是多少位


X86-->32位平台                 X64-->64位平台

二、指针的应用

1、求数组长度

错误求法如下:

void Show(int arr[10])//实际已经退化成指针
{
	sizeof(arr)/sizeof(arr[0]);  //==1,不能求数组的长度
}

int main()
{
	Show(arr,sizeof(arr)/sizeof(arr[0]));  //int *
	return 0;
}

求数组长度的正确求法,代码如下:

void Show(int *arr,int len)
{
	for(int i=0;i<len;i++)
	{
		printf("%d ",arr[i]);
	}
	printf("\n");
}

2、数组元素的逆置

定义一个数组 int arr[5]={1,2,3,4,5};将其中的元素按5,4,3,2,1输出。具体代码如下:

void Reverse(int *arr,int len)
{
	int tmp;
	for(int i=0;i<len/2;i++)
	{
		tmp = arr[i];  //arr[i] == *(arr+i)
		arr[i] = arr[len-1-i];
		arr[len-1-i] = tmp;
	}
}

int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	Reverse(arr,sizeof(arr)/sizeof(arr[0]));
	
	return 0;
}

3、将两值a、b进行交换

以下为三种错误操作代码示例

(1)error1  未建立联系

void Swap(int a,int b)          //error1
{
	int tmp = a;
	a = b;
	b = tmp;
}

int main()
{
	int a = 10;
	int b = 20;

	Swap(a,b);

	printf("%d,%d\n",a,b);

	return 0;
}

上述代码错误原因说明:子函数swap()函数中虽然将a与b进行了交换,但在主函数main()中,又对a、b进行了赋值重新定义,使子函数swap()与主函数间没有构成联系。子函数的a、b与主函数的a、b只是恰巧变量的名称相同。要想使子、主函数间建立起联系就要使用指针进行操作。后面会有介绍。

(2)error2  未解引用

void Swap(int *p1,int *p2)
{
	int tmp;   //没有解引用
	tmp = p1;
	p1 = p2;
	p2 = tmp;
}

说明:①使用指针时需要进行解引用操作,指针才会起作用;

②子函数里仅修改指针的指向,不会影响父函数。需传指针、解引用。

 这里为了帮助理解,引出了“子函数”、“父函数”两个概念。若函数A调用了函数B,则称函数A为父函数,函数B为子函数。

(3)error3  野指针的出现

void Swap(int *p1,int *p2)
{
	int *tmp; //野指针,悬挂指针
	*tmp = *p1; //由此出错,解引用出错,系统崩溃
	*p1 = *p2;
	*p2 = *tmp;
}

无法运行,系统崩溃。

野指针:野指针是指向一个已删除的对象或未申请访问受限内存区域的指针。与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。对野指针进行操作很容易造成程序错误。

成因:①指针变量未初始化;②指针释放后未置空。

避免方法:①初始化时置NULL;②释放时置NULL。

指针未初始化,取随机值,无法访问其值地址,无操作权限,程序无法识别野指针。应养成良好的编程习惯对其进行规避。

(4)正确代码如下:

//子函数的改变要能改变父函数,需传指针,解引用 
void Swap(int *p1,int *p2) 
{
	int tmp;
	tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int main()
{
	int a = 10;
	int b = 20;

	Swap(&p1,&p2);

	return 0;
}