c指针之四:指针和数组

/*数组是c内建的基本数据结构

一、数组概述
获取元素数量的方式 : 数组长度除以元素长度
*/
	int iCount = sizeof(vector) / sizeof(int)
	/*
	1、一维数组
	2、二维数组
	3、多维数组
	二、指针表示法和数组
	单独使用数组名字时候会返回数组地址,可以把数组赋值给指针
		如 :
	*/
int vector[5] = { 1,2,3,4,5 };
int *pv = vector;

//只用数组名字或者对数组的第一个元素用取地址操作符是等价的,都会返回vector的地址
printf("%p\n", vector);
printf("%p\n", &vector[0]);

/*
数组下标可以用在指针上,如pv[i]等价于 *(pv + i);
给指针加一个整数,会把它持有的地址增加这个整数和数据类型长度的乘积,这一点对于给
数组名字加上整数也适用,下面两个语句等价

*(pv + i)
*(vector + i)
*/

//指针和数组的差别
int vector[5] = { 1,2,3,4,5 };

/*
vector[i],*(vector + i)表达的值一样,但是前者生成的机器码是从vector开始,移动i个位置
后者则是从vector开始,在地址上增加i,两者尽管结果一样,但是生成的机器码却不一样
分析下以下代码
*/
int *pv = vector;

pv = pv + 1; // 正确
vector = vector + 1; // 语法错误,修改了数组所持有的地址
pv = vector + 1; // 正确


/*
三、用malloc创建一维数组
如果从堆上分配内存并把地址赋值给一个指针,那就肯定可以对指针使用数组下标,
并把这块内存当成一个数组, 下面代码中,复制之前的vector内容

*/
int *pv = (int*)malloc(5 * sizeof(int));
for (int i = 0; i < 5; i++)
{
	pv[i] = i + 1;
}

// 指针表示法
for (int i = 0; i < 5; i++)
{
	*(pv + i) = i + 1;
}
```

//注意:这种技术分配一块内存,并把它当成数组,其长度在运行时确定。不过,我们得记得要在用完之后释放内存
/*
四、用realloc调整数组长度
C99标准支持变长数组,如果,没有C99,那就用realloc, 如果数组需要的生命周期比较函数长
那也只能用realloc
练习1 : 实现一个函数,从标准输入字符并放入缓冲区,缓冲区会包含除最后的回车字符之外的所有
	字符
	如果realloc分配成功,不需要再释放buffer,因为realloc会把原来的缓冲区复制到新的缓冲区中,
	再把旧的释放。如果试图释放buffer,十有八九程序会终止,因为我们试图重复释放同一块内存
	练习2 : realloc函数也可以用来减少指针指向的内存。实现trim函数,把字符串开头的空白符删掉

*/

/*
五、传递一维数组
将一维数组作为参数传递给函数实际就是通过值来传递数组地址
如果不知道数组长度,就无法处理器元素,最终结果可能是处理的元素太少,也可能
把数组边界的内存当成数组的一部分,这样往往会造成程序非正常终止
1、数组表示法

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

void TestArray()
{
	int vector[5] = { 1,2,3,4,5 };
	displayArray(vector, 5);
}


//注意:为了确定数组元素数量,使用sizeof是不对的

//2、指针表示法

//<1>
void displayArray(int arr[], int size)
{
	for(int i = 0; i < size; i++)
	{
		printf("%d\n", *(arr + i));
	}
}
// <2>
 void displayArray(int *arr, int size)
{
	   for (int i = 0; i < size; i++)
	   {
		   printf("%d\n", *(arr + i));
	   }
}

 //<3>
void displayArray(int *arr, int size)
{
	for (int i = 0; i < size; i++)
	{
		 printf("%d\n", arr[i]);
	}
}

/*
   六、使用指针的一维数组
	  指针数组
*/

void PointerArray()
{
	int* arr[5];
	for(int i = 0; i < 5; i++)
	{
		arr[i] = (int*)malloc(sizeof(int));

		*arr[i] = i;
	}

	// 等价表示法
	*(arr + i) = (int*)malloc(sizeof(int));
	**(arr + i) = i;

	// 打印
	for(int i = 0; i < 5; i++)
	{
		printf("%d\n", **(arr + i));
	}
}

/*
七、指针和多维数
	可以将多维数组的一部分看做是子数组,比如说,二维数组的每一行都可以看做是
	 一维数组
	 int maxtrix[2][5] = { { 1,2,3,4,5 },{ 6,7,8,9,10 } };
注意两点:
	1、maxtrix返回的地址偏移了第一行的长度,20字节
	2、访问数组第一行第二个元素,*(maxtrix[0] + 1)
*/
/*	
八、传递多维数组
	二维数组当做参数传递
	1、当做指针的数组
	
	//正确做法
	void display2DArray(int arr[][5], int rows);

	void display2DArray(int(*arr)[5], int rows);

   //错误做法
	void display2DArray(int *arr[5], int rows);
 */
 /*
   2、全部当做指针
	  // 声明方式
*/
void display2DArrayUnkonwnSize(int *arr, int rows, int cols)
{

}

void TestUse()
{
	//   调用方式
	display2DArrayUnkonwnSize(&maxtrix[0][0], 2, 5);

	// 内部取值
	int iNum = *(arr + (i*cols) + j);

	//注意不能这样使用数组下标,因为没有将指针声明为二维数组
	int iNum = (arr + i)[j]
}

/*	 
九、动态分配二维数组
	1、分配可能不连续的内存
*/
void AllocateMemory()
{
	int rows = 2;
	int columns = 5;

	int **matrix = (int **)malloc(rows * sizeof(int *));

	matrix[0] = (int *)malloc(columns * sizeof(int));

	for (int i = 0; i < rows; i++)
	{
		matrix[i] = (int*)malloc(columns * sizeof(int)); // 为每个一维数组分配内存
	}
}

// 2、第二种技术,数组所需要的所有内存是一次性分配的
void AllocateMemoryWayTwo()
{
	int rows = 5;
	int columns = 6;

	int *matrix = (int*)malloc(rows*columns * sizeof(int));

	// 后面的代码用到这个数组的时候不能使用下标,必须手动计算索引
	// 下图代码中,每个元素被初始化为其索引的乘积
	for(int i = 0; i < rows; i++)
	{
		for(int j = 0; j < columns; j++)
		{
			*(matrix + (i*columns) + j) = i*j;
		}
	}
}
 

   // 注意不能使用数组下标
/*
十、不规则数组和指针
	不规则数组是每一行的列数不一样的二维数组
	复合字面量是一种C构造,前面看起来像类型转换操作,后面跟着换括号的
	初始化列表
*/
void IrregularArray()
{
	int(*(arr2[])) =
	{
		(int[]) {0,1,2,3},
		(int[]) {4,5},
		(int[]) {6,7,8};
	}
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值