C提高-DAY-4

DAY04

  1. 一维数组、二维数组
  2. 数组类型、数组指针类型、数组指针类型变量
  3. 多维数组

1 一维数组初始化

int a[] = {1, 3, 5}; /* 3个元素 */
int b[5] = {1, 2, 3}; /* a[3], a[4]自动初始化为0 */
int c[10] = { 0 }; /* 全部元素初始化为0 */
memset( c, 0, sizeof(c)); /* 通过memset给数组每个元素赋值为0 */

2 数组类型

/**
 * a:数组首行首元素地址,一级指针
 * &a:整个数组的首地址,二级指针
 * 首行首元素地址和首行(整个一维数组)地址值虽然一样,但是它们的步长不一样。
 * a+1:跳过1元素,一元素为4字节,步长4个字节
 * &a + 1:跳过整个数组,整个数组长度为 3 * 4 = 12;步长 3 * 4 = 12
*/
int a[] = {1, 3, 5}; /* 3个元素 */
/* sizeof(a):传参为数组首航首元素地址,测数组(int [3])长度, 3 * 4 = 12
 * sizeof(a[0]):传参为数组首元素(不是地址),每个元素为int类,4字节
 * sizeof(&a):传参为一维数组整个数组的地址(首行地址),编译器当作指针类型,4字节
 */

首行地址 => 首行首元素地址(加*)
&a:首行地址
*&a => a :首行首元素地址

	//数组也是一种数据类型,类型本质:固定大小内存块别名
	//由元素类型和内存大小(元素个数)共同决定 int a[5]  int[5]
	//可以通过typedef定义数组类型
	
	//有typedef:类型
	//没有typedef:变量
	typedef int ARRARY[5]; //定义了一个名字为ARRARY的数组类型
	//等价于typedef int (ARRARY)[5];
	
	//根据数组类型,定义变量
	//ARRARY的位置替代为d,去掉typedef,int d[5]
	ARRARY d;	//相当于int d[5];

3 数组指针变量(它是指针变量,指向数组的指针)

/* 定义数组变量 */
int a[10];
/**
 * 有typedef:类型
 * 没有typedef:变量
*/

3.1 根据数组类型,定义指针变量,数组指针变量

typedef int ARRARY[10]; /* 定义了一个名字为ARRARY的数组类型 */
/* 等价于typedef int (ARRARY)[10]; */
ARRARY *p; /* 数组指针变量 */

int a[10];
/* 编译会有警告,但不会出错,因为a和&a的值一样
 * 就算 p = a这样赋值,编译器内部也会自动转换为 p = &a;
 * 不建议这么做
 */
p = a; 
//p 指向a数组,指向一维数组的指针
p = &a;
//如何操作数组指针变量p
int i = 0;
for(i = 0; i < 10; i++){
	(*p)[i] = i + 1; // *((*p) + i) = i + 1
}

3.2 直接定义数组指针变量(常用)

	//()[]同级,从左往右看
	//()有*,它是一个指针,[]代表数组
	//指向数组的指针变量,[]中的数字代表指针+1的步长
	int(*p)[10]; 
	
	//p 指向a数组,指向一维数组的指针
	p = &a;  

3.3 先定义数组指针类型,再根据类型定义指针变量(常用)

	//数组指针类型,加上typedef
	typedef int(*Q)[10];
	Q p;  //根据类型定义变量,p是数组指针变量
	p = &a; //p指向数组a

4 多维数组本质

4.1 二维数组初始化

	int a1[3][4] = {
		{1, 2, 3, 4},
		{5, 6, 7, 8},
		{9, 10, 11, 12}
	}; 

	int a2[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

	int a3[][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

4.2 内存中并不存在多维数组,多维数组在内存中都是线性储存

	int a[3][5] = { 0 };
	int *b = (int *)a;
	int i = 0;
	for(i = 0; i < 15; i++)
	{
		printf("%d ", b[i]);
	}

4.3 多维数组名

/* 学会类比 */
int b[5] = {0};
b: 首行首元素地址, +1,跳 4 个字节
&b:首行地址,+1,跳 4*5 = 20个字节

/* 二维数组实际上就是 N 个一维数组
 * 把二维数组第一个[]的值看做标志位,0 -> 2
 * 第0个一维数组a[5] -> 第2个一维数组a[5]
*/
/* a是首行地址,相当于一维数组整个数组的地址,相当于上面的 &b,本来就是一个二级指针 */
int a[3][5] = { 0 };
/* (重要)首行地址 =》 首行首元素地址(加*)
 *  *a:首行首元素地址,相当于一维数组首元素地址,相当于上面的 b
 *  a + i -> &a[i]: 第i行地址
 *  *(a+i) -> *&a[i] -> a[i]: 第i行首元素地址
 *  *(a+i)+j -> a[i]+j -> &a[i][j]: 第i行j列元素的地址
 *  *(*(a+i)+j) -> a[i][j]: 第i行j列元素的值
 */
int a[3][5] = { 0 };
sizeof(a): 二维数组整个数组长度,4 * 3 * 5 = 60
sizeof(a[0]):a[0]为第0行首元素地址,相当于测第0行一维数组的长度:4 * 5 = 20
sizeof(a[0][0]):a[0][0]为第00列元素(是元素,不是地址),测某个元素长度:4字节

4.4 多维数组名,实际上是一个数组指针,指向数组的指针,步长为一行字节长度

int a[3][5] = { 0 };

//定义一个数组指针类型的变量
int(*p)[5];

//编译会有警告,但不会出错,因为 a 和 &a的值一样
//但是&a代表整个二维数组的首地址
//就算p = &a这样赋值,编译器内部也会自动转换为 p = a
//不建议这么做
p = &a; 

//a 本来就是第0个一维数组整个数组的地址,所以,无需加&
p = a; 

4.5 二维数组做形参的三种形式

//一维数组做函数参数退化为一级指针
//二维数组(多维数组)做函数参数,退化为数组指针

int a[3][5] = { 0 };

void print_array1(int a[3][5]);

//第一维的数组,可以不写
//第二维必须写,代表步长,确定指针+1的步长 5*4
void print_array2(int a[][5])

//形参为数组指针变量,[]的数字代表步长
void print_array3(int (*a)[5]);

//a+1和二维数组的步长不一样
//这里的步长为4
//上面二维数组的步长为 5 * 4 = 20
void print_array3(int **a); //err

5 指针数组(它是数组,每个元素都是指针)

5.1 指针数组的定义

//指针数组变量
//[]优先级比*高,它是数组,每个元素都是指针(char *)
char *str[] = { "111", "2222222" };

char **str = { "111", "2222222" }; //err

5.2 指针数组做形参

void fun(char *str[]);
void fun(char **str); //str[] -> *str

5.3 main函数的指针数组

//argc: 传参数的个数(包含可执行程序)
//argv:指针数组,指向输入的参数
int main(int argc, char *argv[]);

: demo.exe a b test
int argc = 4
char *argv[] = {"demo.exe", "a", "b", "test"}
	
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值