原文:https://mp.weixin.qq.com/s/0WTjpyfQnT9fNciFy-oP1A
数组
数组由一系列相同数据类型的元素组成。
初始化
void initArrayTemp() {
// 含有 40 个char 类型的数据, 方括号中的数字表明数组中元素的个数
char name[40];
// 含有 8 个 int 类型的数据, 初始化了 8 个元素
int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// 数组元素下标从0开始,a[0] 代表第一个元素
printf("%d\n", a[1]);
printf("初始化值小于数组个数:\n");
// 初始化的元素少于数组个数,那么剩余的值存储的垃圾值,初始化为0
int b[4] = {8};
for (int i = 0; i < 4; ++i) {
printf("%d ", b[I]);
}
printf("\n初始化值大于数组个数:\n");
// 初始化的元素大于数组个数,去调用的话会直接报错
int c[4] = {8, 1, 2, 3, 4, 5, 6, 77};
for (int i = 0; i < 15; ++i) {
printf("%d ", c[I]);
}
printf("\n不设定数组个数:\n");
// 如果初始化数组时省略方括号中的数字,编译器会根据初始化列表中的项数来确定数组的大小
int d[] = {1, 2, 3, 4, 5, 6, 9, 11, 23};
// sizeof运算符给出它的运算对象的大小(以字节为单位)。所以sizeof(d)是整个数组的大小(以字节为单位),sizeof(d[0])是数组中一个元素的大小(以字节为单位)。整个数组的大小除以单个元素的大小就是数组元素的个数。
for (int j = 0; j < sizeof(d) / sizeof(d[0]); ++j) {
printf("%d ", d[j]);
}
printf("\n指定初始化某个元素:\n");
// 在初始化列表中使用带方括号的下标指明待初始化的元素
int e[15] = {1, 2, [3] = 9, [9] = 88, [14] = 3};
for (int k = 0; k < 15; ++k) {
printf("%d ", e[k]);
}
}
2
初始化值小于数组个数:
8 0 0 0
初始化值大于数组个数:
8 1 2 3 8 0 0 0 1 2 3 4 5 6 7
不设定数组个数:
1 2 3 4 5 6 9 11 23
指定初始化某个元素:
1 2 0 9 0 0 0 0 0 88 0 0 0 0 3
赋值
int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
for (int i = 0; i < 8; ++i) {
printf("%d ", a[I]);
}
printf("\n给下标为3的第四个元素赋值\n");
a[3] = 78;
for (int i = 0; i < 8; ++i) {
printf("%d ", a[I]);
}
1 2 3 4 5 6 7 8
给下标为3的第四个元素赋值
1 2 3 78 5 6 7 8
多维数组
// 含6个数组元素的数组,每个数组元素内含12个int类型的元素
int a[6][12] = {
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
};
for (int i = 0; i <5; ++i) {
printf("\n");
for (int j = 0; j < 12; ++j) {
printf("a[%d][%d]=%d ", i, j, a[i][j]);
}
}
printf("\n多维数组赋值1\n");
int b[2][3] = {{1,2}, {2, 3}};
for (int k = 0; k < 2; ++k) {
for (int i = 0; i < 3; ++i) {
printf("b[%d][%d]=%d ", k, i, b[k][I]);
}
}
printf("\n多维数组赋值2\n");
int e[2][3] = {1,2, 2, 3};
for (int k = 0; k < 2; ++k) {
for (int i = 0; i < 3; ++i) {
printf("e[%d][%d]=%d ", k, i, e[k][I]);
}
}
多维数组赋值1
b[0][0]=1 b[0][1]=2 b[0][2]=0 b[1][0]=2 b[1][1]=3 b[1][2]=0
多维数组赋值2
e[0][0]=1 e[0][1]=2 e[0][2]=2 e[1][0]=3 e[1][1]=0 e[1][2]=0
指针
指针提供了一种以符号形式使用地址的方法,能够更有效的处理数组。
- 指针的值是它所指向对象的地址;
- 在指针前面使用
*
运算符可以得到指针指向的对象的值; - 指针加1的值是指针的值增加它指向的类型的大小(字节);
数组名是数组首元素的地址:
int a[10] = {1, 3, 4}; // a 是数组 a 的首元素地址 &a[0]
printf("%p", a); // 通常以十六进制 %p 来表示元素指针的值: 0x7ffee9b61ae0
int *addrA = a; // 可以把指针地址赋值给指针变量
printf("%p\n", addrA); // 0x7ffee9b61ae0
a 和 &a[0] 都表示数组首元素的内存地址,而且都是常量。这个地址值可以赋值给指针变量。
printf("a + 1 = %p\n", a + 1); // 0x7ffee7730ae4
printf("a + 2 = %p\n", a + 2); // 0x7ffee7730ae8
c 语言中,指针加1指增加一个存储单元。 int 占4字节,所以数组中指针加1指的是下一个元素的地址。指针所指向对象的类型一定要知道,这样才能知道存储单元的大小,
printf("%p = %p\n", (a + 2), &a[2]); // 0x7ffee2fc0ae8 = 0x7ffee2fc0ae8
printf("%d = %d", *(a + 2), a[2]); // 4 = 4
知道正确的存储单元大小,*a
才能正确的取回地址对应的值。
函数与指针
// 这个方法的参数是数组的首元素地址, 也可以使用 int a[] 代替更能明确声明的是一个数组形参
int sumArray(int *a, int arraySize){
int total = 0;
int i = 0;
for (i = 0; i < arraySize ; ++i) {
total += a[i]; // a[i] == *(a + i)
}
return total;
}
int a[5] = {1, 2, 3, 4, 5};
printf("total = %d", sumArray(a, 5)); // total = 15
可以在函数中修改传入的数组的元素值
void resetArrayToZero(int a[], int arraySize){
printf("\nreset array to zero:\n");
for (int i = 0; i < arraySize; ++i) {
a[i] = 0; // 相当与直接修改地址对应的值,即原始数据的内容会被修改
}
}
int b[5] = {2, 3, 4, 5, 1};
printf("\noriginal array to zero:\n");
for (int i = 0; i < 5; ++i) {
printf("%d ", b[I]);
}
resetArrayToZero(b, 5);
for (int i = 0; i < 5; ++i) {
printf("%d ", b[I]);
}
original array to zero:
2 3 4 5 1
reset array to zero:
0 0 0 0 0
可以用指针修改数组之外类型的值:
printf("\n修改值:\n");
int number = 4;
changeNumber(number);
printf("changeNumber(int a) -> %d\n", number);
changeNumberByPointer(&number);
printf("changeNumberByPointer(int * a) -> %d\n", number);
修改值:
changeNumber(int a) -> 4
changeNumberByPointer(int * a) -> 16
指针骚操作
- 赋值:地址赋给指针
int attr = &number
; - 解引用:* 号运算符能得到指针指向地址上存储的值;
- 取址:指针变量也有自己的地址和值;
- 指针与整数相加:整数和指针指向的类型大小字节相乘,将结果与指针存储的地址相加;
- 递增指针:递增指向数组元素的指针可以让该指针移动至数组的下一个元素;
- 指针与整数相减:同4,不过是结果相减;
- 递减指针:同5;
- 指针求差:计算两个指针的差值,可以得到数组两个元素的距离,也就可以计算出数组指定类型的大小,两个指针指向同一个数组,这样求差才有意义;
- 用关系运算符可以比较两个指针的值,前提是两个指针都指向相同类型的对象。
形式参数使用 const
int sum(const int ar[], int n); /*函数原型*/
int sum(const int ar[], int n) /*函数定义*/
{
int I;
int total = 0;
for( i = 0 ; i < n ; i++)
total + = ar[i];
return total;
}
形式参数使用 const,指明该参数只读,不能被修改,一旦修改就会编译报错。
指向多维数组的指针
int (*pz)[2]; //pz指向一个内含两个int类型值的数组
int *pax[2]; //pax是一个内含两个指针元素的数组,每个元素都指向int的指针, 中括号的优先级高于 *
int zippo[4][2] = {{2,4},{6,8},{1,3},{5,7}};
int (*pz)[2];
pz = zippo;
zippo[m][n] == *(*(zippo + m) + n)
pz[m][n] == *(*(pz + m) + n)
pz[0][0] = 2
*pz[0] = 2
**pz = 2
pz[2][1] = 3
*(*(pz + 2) + 1) = 3
复合字面量
字面量是除符号常量外的常量。例如,43是int类型字面量,11.3是double类型的字面量,'B'是char类型的字面量,"victor"是字符串字面量。
int a[2] = {1, 2};
(int [2]){1, 2}; // 复合字面量,与数组a相同,是匿名数组,小括号中的 `int [2]` 是复合字面量的类型名
(int []{1, 2, 3}); // 初始化有数组名的数组时可以省略数组大小,复合字面量也可以省略大小,编译器会自动计算数组当前的元素个数
因为复合字面量是匿名的,所以不能先创建然后再使用它,必须在创建的同时使用它。
int *pt1;
pt1 = (int [2]){10, 20};
小结
数组属于派生类型,因为它是建立在其他类型的基础上使用的。通常会使用函数来处理数组,在把数组名作为实际参数时,传递给函数的不是整个数组,而是数组的地址(因此,函数对应的形式参数是指针)。
要明确数组,指针的基本概念保持头脑清晰,这样才能轻松应对多维数组。
网友评论