Loading

指针和数组


返回 我的技术栈(Technology Stack)



数组名

数组名字是数组的首元素地址,但它是一个常量,不允许被赋值
具体的说:
在C中,在几乎所有使用数组名的表达式中,数组名的值是一个指针常量,也就是数组第一个元组的地址
它的类型取决于数组元素的类型:
如果数组是int类型,那么 数组名的类型 就是“指向int的常量指针”;
如果数组是其他类型,那么 数组名的类型 就是“指向其他类型的常量指针”。
注意这个值是指针常量,而不是指针变量。你不能修改常量的值。
这很好理解,指针常量所指向的是内存中数组的起始位置,如果修改这个指针常量,唯一可行的操作就是把整个数组移动到内存的其他位置。但是,在程序完成链接之后,内存中数组的位置是固定的,所以当程序运行时,再想移动数组就为时已晚了,因此,数组名的值就是一个指针常量。

#include<stdio.h>

int main(void) 
{
	int arr[] = { 10,4,5,1,2,3,8,9,13};
	
	//【注意:数组名是一个常量,不允许赋值】
	// 数组名 是 数组首元素地址

	// arr = 100; //报错!!!!这个操作是相当于修改首元素的地址

	int* p;
	p = arr;
	printf("%p\n", p);      // 输出:006FFCAC
	printf("%d\n", *p);    // 输出:10
	printf("%p\n", arr);    // 输出:006FFCAC
	printf("%d\n", *arr);    // 输出:10

	return 0;
}

指针数组

指针数组,它是数组,数组的每个元素都是指针类型。

#include <stdio.h>

int main()
{
	//指针数组
	int *p[3];
	int a = 1;
	int b = 2;
	int c = 3;
	int i = 0;

	p[0] = &a;
	p[1] = &b;
	p[2] = &c;

	for (i = 0; i < sizeof(p) / sizeof(p[0]); i++ )
	{
		printf("%d, ", *(p[i]));
	}
	printf("\n");
	
	return 0;
}
#include <stdio.h>

int main()
{
	int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int* p2 = &a[2]; //第2个元素地址
	int* p1 = &a[1]; //第1个元素地址
	printf("p1 = %p, p2 = %p\n", p1, p2);

	int n1 = p2 - p1; //n1 = 1
	int n2 = (int)p2 - (int)p1; //n2 = 4
	printf("n1 = %d, n2 = %d\n", n1, n2);

	return 0;
}

指针操作数组元素

直接看代码和注释吧!

#include<stdio.h>

int main(void) 
{
	int arr[] = {10,4,5,1,2,3,8,9,13};
	
	//【注意:数组名是一个常量,不允许赋值】
	// 数组名 是 数组首元素地址

	// arr = 100; //报错!!!!这个操作是相当于修改首元素的地址

	int* p;
	p = arr;
	printf("%p\n", p);      // 输出:006FFCAC
	printf("%d\n", * p);    // 输出:10
	printf("%p\n", arr);    // 输出:006FFCAC
	printf("%d\n", *arr);   // 输出:10


	printf("%d\n", sizeof(arr) );  //输出:36
	printf("%d\n", sizeof(arr[0]));  //输出:4
	printf("%d\n", sizeof(arr) / sizeof(arr[0]));  //输出:9

	for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) 
	{
		//printf("%d\t", arr[i]);  //输出:10      4       5       1       2       3       8       9       13
		printf("%d\t",p[i]);   //输出:10      4       5       1       2       3       8       9       13
	}

	//问题:对于用地址取值来说,到底加多少?
	printf("%d\n",*(arr+1));  //输出:4
	printf("%d\n",*(arr+4));  //输出:2
	//原因:
	//指针类型变量 +1 操作,等同于内存地址 + sizeof(int) , 因为我们这里指针类型为 int* p; 或 int arr[];
	//如果是一个int *,+1的结果是增加一个int的大小
	//如果是一个char *,+1的结果是增加一个char大小


	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		//这是地址,我们转成10进制输出;可以看出每个地址是相加了 4 的,也就是一个int类型大小
		printf("%d\t", (p+i));   //输出:5241048        5241052        5241056        5241060        5241064        5241068        5241072        5241076        5241080
		//printf("%d\t", *(p+i));   //输出:10      4       5       1       2       3       8       9       13
		//printf("%d\t", p[i]);     //输出:10      4       5       1       2       3       8       9       13
		
		//先算 *p   再算 p++
		printf("%d\t",*p++);   //输出:10      4       5       1       2       3       8       9       13
	}

	//这是地址,我们转成10进制输出;
	printf("%d\n",arr);        //  输出:5241048
	printf("%d\n", arr + 1);  //输出:5241052

	//经过上面 *p++ 操作后,p的地址和arr不一样了,【而且,这个时候指针指向是不是最后一个元素地址,而是下一个,可以说是下标越界了一个,也就是野指针了】
	printf("%d\n",p);          //  输出:5241084


	return 0;
}

指针和数组区别

#include<stdio.h>

int main(void) 
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	//指向数组的指针
	int* p = arr;

	//区别:
	//p是变量;arr是常量
	//p是一个指针占4字节大小;arr是一个数组占40字节大小
	printf("指针类型大小:%d\n", sizeof(p));   //输出:4
	printf("数组大小:%d\n", sizeof(arr));   //输出:40

	return 0;
}

冒泡排序为什么要传入长度len

#include<stdio.h>

void BubbleSort(int arr[], int len)
{

	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}

}

int main(void) 
{
	int arr[] = { 10,4,5,1,2,3,8,9,13};
	int len = sizeof(arr) / sizeof(arr[0]);

	BubbleSort(arr, len);

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

	return 0;
}

对于一个冒泡排序算法,我们需要传入一个len,那,既然传入了arr,我们为什么不在排序函数里面直接计算 出len呢,省去一个参数传递。
但是,下面程序证明这是不行的。

#include<stdio.h>

void BubbleSort(int arr[]) //这里 arr 相当于传入的是一个指针(类型)
{
	//主要原因:数组作为函数参数传递时,实际上传递的是数组的 首地址 。相当于是一个指针
	//那么,一个指针类型,是有固定大小的,比如在32位操作系统就是4字节大小
	int len = sizeof(arr) / sizeof(arr[0]);
	printf("%d\n", len);   // 输出:1      这相当于是 4/4=1

	int len1 = sizeof(arr);   // arr 相当于是一个指针
	printf("%d\n", len1);   // 输出:4
}

int main(void) 
{
	int arr[] = { 10,4,5,1,2,3,8,9,13};
	
	BubbleSort(arr);

	return 0;
}

也就是说,下面代码的对 arr 的一系列操作并不是对数组的,而是对指针的操作

void BubbleSort(int arr[], int len)
{

	for (int i = 0; i < len - 1; i++)
	{
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (arr[j] > arr[j + 1])
			{
				int temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}

}

即之前展示的这种方式:

#include<stdio.h>

int main(void) 
{
	int arr[] = { 10,4,5,1,2,3,8,9,13};

	int* p;
	p = arr;
	
	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		//这是地址,我们转成10进制输出;可以看出每个地址是相加了 4 的,也就是一个int类型大小
		printf("%d\t", (p+i));
		//printf("%d\t", *(p+i));   //输出:10      4       5       1       2       3       8       9       13
		//printf("%d\t", p[i]);     //输出:10      4       5       1       2       3       8       9       13
		//先算 *p   再算 p++
		printf("%d\t",*p++);   //输出:10      4       5       1       2       3       8       9       13
	}
	
	return 0;
}

参考:
[1]C基础讲义2018修订版(黑马程序员)
[2]C和指针/(美)里科(Reek,K.A.)著;徐波译.——北京:人民邮电出版社,2008.4(2011.10重印)


posted @ 2021-07-20 17:01  言非  阅读(54)  评论(0编辑  收藏  举报