title: 第十章 数组和指针
author: HardyDragon
tags: C Notes
第十章 数组和指针
-
初始化数组
float candy[365];
-
初始化数组
int days[] = {1,2,3};
-
指定初始化器(C99)
// designate.c -- 使用指定初始化器 #include <stdio.h> #define MONTHS 12 int main(int argc, char const *argv[]) { int days[MONTHS] = {31, 28, 31, 30, 31}; int i; for (i = 0; i < MONTHS; i++) { printf("%2d %d\n", i + 1, days[i]); } return 0; }
result:
1 31 2 28 3 31 4 30 5 31 6 0 7 0 8 0 9 0 10 0 11 0 12 0
-
二维数组
// designate.c -- 使用指定初始化器 #include <stdio.h> #define MONTHS 12 int main(int argc, char const *argv[]) { int days[2][3] = {{1, 2, 3}, {4, 5, 6}}; int i, j; for (i = 0; i < 2; i++) { for (j = 0; j < 3; j++) { printf("%d \t", days[i][j]); } putchar('\n'); } return 0; }
result:
1 2 3 4 5 6
-
指针和数组
#include <stdio.h> int main() { char arr[10] = {0}; if (arr == &arr[0]) { printf("equal!\n"); printf("size:%d", sizeof(arr)); } return 0; }
result:
equal! size:10
数组名就是一个指针,其大小为数组的大小。
#include <stdio.h> int main() { char* ap; char arr[10] = {'a'}; ap = arr; if (arr == &arr[0]) { printf("equal!\n"); printf("sizeof(arr) = size:%d\n", sizeof(arr)); printf("*ap = %c\n",*ap); } return 0; }
result:
equal! sizeof(arr) = size:10 *ap = a
#include <stdio.h> int main() { char *ap; char arr[5] = {'a', 'a', 'a', 'a', 'a'}; int i; ap = arr; if (arr == &arr[0]) { printf("equal!\n"); printf("sizeof(arr) = size:%d\n", sizeof(arr)); printf("sizeof(arr[0]) = size:%d\n", sizeof(arr[0])); printf("*ap = %c\n", *ap); printf("*arr = %c\n", *arr); } for (i = 0; i < 5; i++) { printf("%c\t", arr[i]); } return 0; }
result:
equal! sizeof(arr) = size:5 sizeof(arr[0]) = size:1 *ap = a *arr = a a a a a a
数组名的值是第一个数组元素的值。
#include <stdio.h> int main() { int *ap; int arr[5] = { 1, }; if (arr + 2 == &arr[2]) { printf("arr + 2 == &arr[2] equal!\n"); printf("*(arr + 2) = %d,arr[2] = %d\n", *(arr + 2), arr[2]); } for (int i = 0; i < 5; i++) { /* code */ printf("%d\t", arr[i]); } putchar('\n'); return 0; }
result:
arr + 2 == &arr[2] equal! *(arr + 2) = 0,arr[2] = 0 1 0 0 0 0
注意初始化时候如果以这种形式初始化就会将剩余元素初始化为0
int arr[5] = { 1, };
指针的加法,数组名就是一个指针,即数组名+2等于指针加上对应的数据类型大小,例如int的话就是+8了,跳过两个int的元素,便到了第三个数组元素,即arr[2];
-
将数组以指针的形式传入函数以解决函数间的通信问题。
声明数组形参的4中方法,函数原型:
int sum(int* arr, int n); int sum(int*, int); // 函数定义不可以 int sum(int arr[], int n); int sum(int [], int); // 函数定义不可以
但是在函数定义中不能省略参数名
所以一般使用其他 两种来声明和定义函数的参数。
// sum_arr1.c -- 数组元素之和 #include <stdio.h> #define SIZE 5 int sum(int *arr, int n); int main(int argc, char const *argv[]) { int arr[SIZE] = {1, 2, 3, 4, 5}; long answer; answer = sum(arr, SIZE); printf("total = %d\n", answer); return 0; } int sum(int *arr, int n) { int total = 0; for (int i = 0; i < SIZE; i++) { total += arr[i]; } printf("total = %d\n", total); return total; }
result:
total = 15 total = 15
也可以换一种函数声明和定义,结果一样,写法等价,但是便于理解还是统一形式较好:
// sum_arr1.c -- 数组元素之和 #include <stdio.h> #define SIZE 5 int sum(int arr[], int n); int main(int argc, char const *argv[]) { int arr[SIZE] = {1, 2, 3, 4, 5}; long answer; answer = sum(arr, SIZE); printf("total = %d\n", answer); return 0; } int sum(int arr[], int n) { int total = 0; for (int i = 0; i < SIZE; i++) { total += arr[i]; } printf("total = %d\n", total); return total; }
记住数组名就是一个指针,指向数组的第一个元素,但其大小是整个数组的 大小,而非一个元素的大小。
-
使用指针形参明确数组的遍历起始和终止位置。
// sum_arr2.c -- 数组元素之和 #include <stdio.h> #define SIZE 5 int sum(int *start, int *end); int main(int argc, char const *argv[]) { int arr[SIZE] = {1, 2, 3, 4, 5}; long answer; answer = sum(arr, arr + SIZE); printf("total = %d\n", answer); return 0; } int sum(int *start, int *end) { int total = 0; while (start < end) { /* code */ total += *(start); start++; } printf("total = %d\n", total); return total; }
result:
total = 15 total = 15
可以通过指针+数组大小确定数组的最后一个元素的地址(指针)。
可以修改一下函数定义来用指针对数组求和。
因为指向数组最后一个位置后面的指针(即end指针)仍是有效的指针,这使得while的循环测试条件是有效的。这种指针称为“越界指针”,或许对函数的调用更为简洁。
可以将循环体压缩成一行代码
total += *start++;
一元运算符*和++优先级相同,但是结合律从右往左,所以start++先求值,再是 *start 。
取值是可以用数组表示法或者指针表示法。arr[i] 或者 *(arr+i)
#include <stdio.h> int main() { int arr[5]; if (arr[2] == *(arr + 2)) { printf("equal!\n"); } return 0; }
result:
equal!
-
指针操作
指针求差表示的是两个指针相差的多少个对应的数据类型。指针没有相加、乘除操作
-
注意不要对未初始化的指针去直接赋值,因为不知道会不会直接覆盖其他内存的数据。
如果函数的意图不是修改数组中的数据内容,应当使用const关键字将数组变为只读类型的数据。可以对函数声明中的数组使用const关键字
-
指针和多维数组
读取多维数组的值
#include <stdio.h> int main() { int arr[2][3] = {{1, 2, 3}, {4, 5, 6}}; printf("arr[0][1]=%d\n", arr[0][1]); printf("**arr=%d\n", **arr); return 0; }
result:
arr[0][1]=2 **arr=1
指向多维数组的指针:
首先明确声明指针数组和 数组指针的两个方式:
int (*ap)[2]; // int arr[2]; (*ap) 相当于数组名 int* ap[2]; // int* ap; ap[2] 相当于指针名
[] 的优先级高于 *
// zippo2.c -- 指针指向多维数组 #include <stdio.h> int main(int argc, char const *argv[]) { int arr[4][2] = {{2, 4}, {6, 8}, {1, 3}, {5, 7}}; int(*ap)[2]; // int arr[2]; (*ap) 相当于数组名 ap = arr; printf("pz[0][0]=%d\n", ap[0][0]); printf("*ap[0]=%d\n", *ap[0]); printf("**ap=%d\n", **ap); printf("ap[2][1]=%d\n", ap[2][1]); printf("*(*(ap + 2) + 1)=%d\n", *(*(ap + 2) + 1)); return 0; }
result:
pz[0][0]=2 *ap[0]=2 **ap=2 ap[2][1]=3 *(*(ap + 2) + 1)=3
这是一个难点,但是不需要深入的理解,因为不常用,就算用也有较好的解决方案,将多维数组封装在结构体中去在解决实际问题上可能比较方便,详情可查看b站的C语言中文网有关指针的视频里面有讲到。
例如以上便解决了多维数组传递给函数的参数写法。这个多维数组不太好理解,暂时我认为不必深究。
-
复合字面量
需要在创建的时候就使用,相当于一个lambda函数一样。可以用于给指针赋值。
int* ap; ap = (int[2]){10,20};
复合字面量是提供临时需要的值的一种手段。有些编译器不支持。
return 0;
}
result:
pz[0][0]=2
*ap[0]=2
**ap=2
ap[2][1]=3
((ap + 2) + 1)=3这是一个难点,但是不需要深入的理解,因为不常用,就算用也有较好的解决方案,将多维数组封装在结构体中去在解决实际问题上可能比较方便,详情可查看b站的C语言中文网有关指针的视频里面有讲到。 [外链图片转存中...(img-MAMfMrv7-1616426046625)]
例如以上便解决了多维数组传递给函数的参数写法。这个多维数组不太好理解,暂时我认为不必深究。
-
复合字面量
需要在创建的时候就使用,相当于一个lambda函数一样。可以用于给指针赋值。
int* ap; ap = (int[2]){10,20};
复合字面量是提供临时需要的值的一种手段。有些编译器不支持。