主要回顾 C 语言数组、枚举和指针。
# 概念
- 数组特点
- 固定大小
- 元素类型相同
- 内存连续(最低的地址对应第一个元素,最高的地址对应最后一个元素)
- 下标从 0 开始
- 若省略掉了数组的大小,数组的大小则为初始化时元素的个数
- blabla...
# 代码
#include <stdio.h> | |
/* | |
定义数组 | |
(1)外部定义的数组,默认初始值都是 0,而函数内部定义的初始值可能有脏值 | |
*/ | |
int arrOutside[10]; | |
int main1(){ | |
int arrSize; | |
arrSize = sizeof(arrOutside) / sizeof(arrOutside[0]); | |
for (int i = 0; i < arrSize; i++){ | |
printf("arrOutside[%d] = %d\n", i, arrOutside[i]); | |
} | |
int arr1[5] = {1, 2, 3, 4, 5}; | |
arrSize = sizeof(arr1) / sizeof(arr1[0]); | |
printf("arr1 size = %d \n", arrSize); | |
//int arr2 [5] = {1, 2, 3, 4, 5, 6}; // 报 too many initializer values | |
// 省略掉了数组的大小,数组的大小则为初始化时元素的个数 | |
int arr3[] = {1, 2, 3, 4, 5, 6}; | |
arrSize = sizeof(arr3) / sizeof(arr3[0]); | |
printf("arr3 size = %d \n", arrSize); | |
//arr4 和 arr5 未赋值位置的值是不确定的(脏值),所以定义数组一定要初始化值为 0 | |
int arr4[5]; | |
arr4[3] = 3; | |
arrSize = sizeof(arr4) / sizeof(arr4[0]); | |
printf("arr4 size = %d \n", arrSize); | |
for (int i = 0; i < arrSize; i++){ | |
printf("arr4[%d] = %d\n", i, arr4[i]); | |
} | |
int arr5[5]; | |
arrSize = sizeof(arr5) / sizeof(arr5[0]); | |
printf("arr5 size = %d \n", arrSize); | |
for (int i = 0; i < arrSize; i++){ | |
printf("arr5[%d] = %d\n", i, arr5[i]); | |
} | |
} | |
/* | |
测试数组扩充 | |
*/ | |
int main2(){ | |
printf("--------------------\n"); | |
int numbers[5] = {0, 1, 2, 3, 4}; | |
int arrSize = sizeof(numbers) / sizeof(numbers[0]); | |
printf("数组长度是 %d \n", arrSize); | |
for (int i = 0; i < arrSize; i++){ | |
printf("numbers[%d] = %d\n", i, numbers[i]); | |
} | |
numbers[6] = 5; | |
numbers[7] = 6; | |
numbers[8] = 7; | |
printf("numbers[8] = %d\n", numbers[8]); | |
printf("numbers[9] = %d\n", numbers[9]); | |
printf("--------------------\n"); | |
int newArrSize = sizeof(numbers) / sizeof(numbers[0]); | |
printf("数组长度变为 %d \n", newArrSize); | |
for (int i = 0; i < newArrSize; i++){ | |
printf("numbers[%d] = %d\n", i, numbers[i]); | |
} | |
printf("--------------------\n"); | |
int initialNumbers[10] = {0}; // 前 10 个元素初始值为 0,后面 99 个有变化 | |
int theArrSize = sizeof(initialNumbers) / sizeof(initialNumbers[0]); | |
printf("数组长度变为 %d \n", theArrSize); | |
for (int i = 0; i < 100; i++){ | |
printf("numbers[%d] = %d\n", i, initialNumbers[i]); | |
} | |
return 0; | |
} | |
/* | |
给定 n 个学生的成绩,要求有多少学生超过了平均分 | |
*/ | |
int main3(){ | |
// 定义数组 | |
int cj[100]={0}; | |
int n; | |
// 定义计数器,统计有多少人达到平均分 | |
int count = 0; | |
scanf("%d", &n); | |
int i = 0; | |
// 读入数据 | |
for (i = 0; i < n; i++){ | |
scanf("%d", &cj[i]); | |
} | |
// 对数据进行求和 | |
double sum = 0; | |
for(i = 0; i < n; i++){ | |
sum += cj[i]; | |
} | |
// 求平均分 | |
double arg = sum/n; | |
// 判断有多少人达到平均分 | |
for(i=0;i<n;i++){ | |
if (cj[i] > arg){ | |
count++; | |
} | |
} | |
// 输出平均分和人数 | |
printf("平均分为:%0.2f\n超过平均分的人有:%d个\n", arg, count); | |
return 0; | |
} | |
/* | |
数组与数组内存地址 | |
*/ | |
int main4(){ | |
//a [0] 、a [1]...a [i] 代表的都是值 | |
int a[2] = {1, 2}; | |
printf("a[0] = %d\n", a[0]); | |
printf("a[1] = %d\n", a[1]); | |
printf("----------------\n"); | |
printf("*a = %d\n", *a); | |
printf("*(a+0) = %d\n", *(a + 0)); | |
printf("*(a+1) = %d\n", *(a + 1)); | |
printf("----------------\n"); | |
//a、(a+0)、(a+1)、(a+i) 代表的是地址 | |
// 且 a 代表整个数组的首地址,相当于 a [0] 的地址 | |
// 这里 (a+1) 就代表的是 a [0+1] 的地址 | |
printf("a 的地址:%p\n", a); | |
printf("(a+0)的地址:%p\n", (a + 0)); | |
printf("(a+1)的地址:%p\n", (a + 1)); | |
printf("(a+2)的地址:%p\n", (a + 2)); | |
printf("(a+3)的地址:%p\n", (a + 3)); | |
return 0; | |
} | |
/* | |
数组初始化注意点 | |
(1)默认值: | |
- 对于 short、int、long,就是整数 0; | |
- 对于 char,就是字符 '\0'; | |
- 对于 float、double,就是小数 0.0。 | |
*/ | |
int main5(){ | |
// 只给部分元素赋值 相当于 只给前面部分元素赋值,后面元素是默认值 | |
// 如下面只给 a [0]~a [4] 5 个元素赋值,而后面 5 个元素自动初始化为 0 | |
int a[10]={12, 19, 22 , 993, 344}; | |
// 可以通过下面的形式将数组的所有元素初始化为 0, 由于剩余的元素会自动初始化为 0,所以只需要给第 0 个元素赋值为 0 | |
int nums[10] = {0}; | |
char str[10] = {0}; | |
float scores[10] = {0.0}; | |
// 只能给元素逐个赋值,不能给数组整体赋值。 | |
int m[10] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; | |
int n[10] = {1}; | |
for(int i=0;i<10;i++){ | |
printf("m[%d] = %d \n", i, m[i]); | |
} | |
printf("-----------------\n"); | |
for(int j=0;j<10;j++){ | |
printf("n[%d] = %d \n", j, n[j]); | |
} | |
return 0; | |
} | |
/* | |
指针与数组名的区别 | |
指针:也是一个变量,存储的是地址 | |
数组名:代表的是该数组最开始的一个元素的地址。 | |
(1)对数组元素 a [i] 的引用也可以写成 *(a+i) 这种形式。 | |
(2)赋值语句 p=&a [0] 也可以写成下列形式: p=a。 | |
(3)p 是个指针,p [i] 与 *(p+i) 是等价的。 | |
区别:指针是一个变量,可以进行数值运算。数组名不是变量,不可以进行数值运算。 | |
*/ | |
int main6(){ | |
int a[10]; | |
int *p; | |
//p = &a; //warning: assignment to 'int *' from incompatible pointer type 'int (*)[10]' | |
//Arrays are not pointers, pointers are not arrays. | |
p = &a[0]; | |
printf("指针(地址)的值为:OX%p\n",p); | |
int n[3][3] = { | |
{2, 4, 3}, | |
{6, 8, 5}, | |
{3, 5, 1} | |
}; | |
int i, *pt; | |
// pt = n; | |
pt = &n[0][0]; | |
for (int i = 0; i <= 8; i++) | |
{ | |
//printf ("% d \n", *(pt + i)); // 等同于下一行 | |
printf("%d \n", pt[i]); | |
} | |
return 0; | |
} | |
/* | |
求数组中最大值和最小值 | |
(1)数组变量是特殊的指针,数组变量本身表达地址,int a [10]; int *p =a; | |
(2)数组变量无需用取址符 & amp; ; | |
(3)数组的元素表达的是变量,需要用 & amp; 取地址,如 m = &a [0]; | |
(4)[] 运算符可以对数组做,也可以对指针做 p [0] == a [0]; | |
(5)* 运算符可以对指针做,也可以对数组做 *a = 25, *a 可以得到或者修改数组首个元素的值; | |
*/ | |
void minMax(int a[], int len, int *min, int *max){ | |
int i; | |
*min = *max = a[0]; | |
for(int i=1;i < len;i++){ | |
if(a[i] < *min){ | |
*min = a[i]; | |
} | |
if(a[i] > *max){ | |
*max = a[i]; | |
} | |
} | |
} | |
int main7(){ | |
int a[] = {1, 2, 3, 4, 5, 7, 8, 9, 15, 18, 25, 33}; | |
int min, max; | |
int len = sizeof(a) / sizeof(a[0]); | |
minMax(a, len, &min, &max); | |
printf("min = %d, max = %d \n", min, max); | |
return 0; | |
} | |
/* | |
数组赋值的区别,下面输出:size a=6, size b=5 | |
a 数组结尾 a [5]=0,而 b 恰好是 5 个空间 | |
*/ | |
int main8(){ | |
char a[] = "jalen"; | |
char b[] = {'j', 'a', 'l', 'e', 'n'}; | |
int size_a = sizeof(a) / sizeof(a[0]); | |
int size_b = sizeof(b) / sizeof(b[0]); | |
printf("size a=%d, size b=%d \n", size_a, size_b); | |
for(int i=0;i<size_a;i++){ | |
printf("a[%d]=%d \n", i, a[i]); | |
} | |
for(int j=0;j<size_b;j++){ | |
printf("b[%d]=%d \n", j, b[j]); | |
} | |
return 0; | |
} | |
/* | |
数组元素置 0 | |
*/ | |
int main9(){ | |
// 一维数组置 0 | |
int a[5] = {0}; | |
int size_a = sizeof(a)/sizeof(a[0]); | |
for(int i=0;i<size_a;i++){ | |
printf("a[%d]=%d\n", i, a[i]); | |
} | |
// 二维数组置 0 | |
int b[3][4] = {0}; | |
int size_b_x = sizeof(b)/sizeof(b[0]); | |
int size_b_y = sizeof(b[0])/sizeof(b[0][0]); | |
for(int i=0;i<size_b_x;i++){ | |
for(int j=0;j<size_b_y;j++){ | |
printf("b[%d][%d]=%d\n", i, j, b[i][j]); | |
} | |
} | |
// 三维数组置 0 | |
int c[2][3][4] = {0}; | |
int size_c_x = sizeof(c)/sizeof(c[0]); | |
int size_c_y = sizeof(c[0])/sizeof(c[0][0]); | |
int size_c_z = sizeof(c[0][0])/sizeof(c[0][0][0]); | |
for(int x=0;x<size_c_x;x++){ | |
for(int y=0;y<size_c_y;y++){ | |
for(int z=0;z<size_c_z;z++){ | |
printf("c[%d][%d][%d]=%d\n", x, y, z, c[x][y][z]); | |
} | |
} | |
} | |
return 0; | |
} | |
/* | |
将枚举、数组和结构体结合使用 | |
下面的程序没有调试通过,backup | |
*/ | |
// struct Student{ | |
// char* name; | |
// int age; | |
// int height; | |
// } ST; | |
// struct Student ST[] = { | |
// {"Jalen", 20, 88}, | |
// {"Moe", 18, 88}, | |
// {"Jones", 30, 99} | |
// }; | |
// enum MEMBER{ | |
// Jalen, | |
// Jones, | |
// Moe | |
// }; | |
// struct Student getStudentInfo(enum MEMBER name){ | |
// return ST[name]; | |
// } | |
// int main(){ | |
// Student stu = getStudentInfo(Jalen); | |
// cout << stu.name << endl; | |
// cout << stu.age << endl; | |
// cout << stu.height << endl; | |
// return 0; | |
// } | |
/* | |
& 取地址:取变量地址 | |
*/ | |
// function to convert decimal to hexadecimal | |
void decToHex(int decNum){ | |
// char array to store hexadecimal number | |
char hexaDeciNum[50]; | |
// counter for hexadecimal number array | |
int i = 0; | |
while (decNum != 0){ | |
/* temporary variable to store right most digit*/ | |
int temp = 0; | |
// Get the right most digit | |
temp = decNum % 16; | |
// check if temp < 10 | |
if (temp < 10){ | |
hexaDeciNum[i] = temp + 48; | |
i++; | |
}else{ | |
hexaDeciNum[i] = temp + 55; | |
i++; | |
} | |
decNum = decNum / 16; // get the quotient | |
} | |
printf("0x"); //print hex symbol | |
// printing hexadecimal number array in reverse order | |
for (int j = i - 1; j >= 0; j--){ | |
printf("%c", hexaDeciNum[j]); | |
} | |
} | |
int main10(){ | |
int a = 1; | |
int *p = &a; | |
//int *s = &100; // 不能对具体值取地址,变量之所以有地址就是因为要有一个存储单元对变量进行标识 | |
printf("The value is %d\n", a); //a 变量的值 = 1 | |
printf("The value is %d\n", *p); // 同样是输出 a 变量的值 = 1 | |
printf("The pointer address value is 0x%p\n", p); // 输出地址 | |
printf("The value is %d\n", &a); // 这里有问题,不是很理解 | |
decToHex(222299536); | |
} | |
/* | |
接收数组参数方式 | |
(1)指针形式 | |
(2)数组形式(带 size 或不带) | |
*/ | |
void getAverage(int *param1, int param2[5], int param3[], int size){ | |
//param1: 形参是一个指针 | |
//param2: 形参是一个已定义大小的数组 | |
//param3: 形参是一个未定义大小的数组 | |
for(int i=0;i<size;i++){ | |
printf("param1[%d]=%d\n", i, param1[i]); | |
printf("param2[%d]=%d\n", i, param2[i]); | |
printf("param3[%d]=%d\n", i, param3[i]); | |
} | |
} | |
int main11(){ | |
int arr[5] = {1, 2, 3, 4, 5}; | |
int size = sizeof(arr)/sizeof(arr[0]); | |
int *p = &arr[0]; | |
getAverage(p, arr, arr, size); | |
} | |
/* | |
枚举 | |
格式:enum 枚举名 {枚举元素 1, 枚举元素 2,……}; | |
按照 C 语言规范是没有办法遍历枚举类型的; | |
不过由于 DAY 是连续的枚举,可以实现遍历,SEASON 是不连续的枚举,所以没法实现 | |
*/ | |
enum DAY { | |
MON = 1, | |
TUE, //2 | |
WED, //3 | |
THU, //4 | |
FRI, //5 | |
SAT, //6 | |
SUN //7 | |
}; | |
enum SEASON { | |
spring, //0 | |
summer = 3, | |
autumn, //4 | |
winter //5 | |
}; | |
int main12(){ | |
enum DAY day = SAT; | |
printf("Today is %d\n", day); | |
enum SEASON season = winter; | |
printf("The season is %d\n", season); | |
// 枚举可用于 switch 语句 | |
enum color { | |
red=1, | |
green, | |
blue | |
}; | |
enum color favorite_color; | |
printf("请输入你喜欢的颜色: (1. red, 2. green, 3. blue): "); | |
scanf("%u", &favorite_color); | |
switch (favorite_color){ | |
case red: | |
printf("你喜欢的颜色是红色"); | |
break; | |
case green: | |
printf("你喜欢的颜色是绿色"); | |
break; | |
case blue: | |
printf("你喜欢的颜色是蓝色"); | |
break; | |
default: | |
printf("你没有选择你喜欢的颜色"); | |
} | |
return 0; | |
} | |
/* | |
指针可用于简化 C 编程 | |
动态内存分配 | |
*/ | |
int main13(){ | |
int age = 20; | |
// 定义指针 | |
int *p; | |
p = &age; | |
printf("变量的地址是 %p\n", &age); | |
printf("指针的地址是 %p\n", p); | |
printf("*p 变量的值: %d\n", *p); | |
// 赋为 NULL 值的指针被称为空指针,NULL 指针是一个定义在标准库中的值为零的常量 | |
// 赋一个 NULL 值是一个良好的编程习惯 | |
int *s = NULL; | |
printf("s的地址是 %p\n", s); | |
return 0; | |
} | |
/* | |
指针的算术运算 | |
C 指针是一个用数值表示的地址。因此可以执行四种算术运算:++、--、+、- | |
上面四种运算其实就是指针在挪动,比如向前、向后移动,int 是移动 4 个字节(int 4 字节 32bit) | |
*/ | |
int main14(){ | |
int a = 10; | |
int *p = &a; | |
printf("address is %p\n", p); | |
p++; | |
printf("address is %p\n", p); | |
p--; | |
printf("address is %p\n", p); | |
p--; | |
printf("address is %p\n", p); | |
return 0; | |
} | |
/* | |
指针数组:可以定义用来存储指针的数组。 | |
*/ | |
int main15(){ | |
int arr[3] = {1, 2, 3}; | |
int *ptr[3]; | |
for(int i=0;i<3;i++){ | |
ptr[i] = &arr[i]; | |
} | |
for(int i=0;i<3;i++){ | |
printf("Address of var[%d] = %d\n", i, ptr[i]); | |
printf("Value of var[%d] = %d\n", i, *ptr[i]); | |
} | |
return 0; | |
} | |
/* | |
指向指针的指针: C 允许指向指针的指针 (多级间接寻址 - 指针链)。 | |
*/ | |
int main16(){ | |
int age = 10; | |
int *p1 = &age; | |
int **p2 = &p1; | |
printf("age = %d\n", age); | |
printf("p1 = %p\n", p1); | |
printf("*p1 = %d\n", *p1); | |
printf("p2 = %p\n", p2); | |
printf("**p2 = %d\n", **p2); | |
return 0; | |
} | |
/* | |
从函数返回指针 | |
下面是要生成和返回随机数的函数 | |
*/ | |
#include <time.h> | |
#include <stdlib.h> | |
int * getRandom(){ | |
int r[10]; | |
int i; | |
// 设置种子 | |
srand( (unsigned)time( NULL ) ); | |
for ( i = 0; i < 10; ++i){ | |
r[i] = rand(); | |
printf("%d\n", r[i] ); | |
} | |
return r; | |
} | |
int main(){ | |
int *p; | |
int i; | |
p = getRandom(); | |
for ( i = 0; i < 10; i++ ){ | |
//printf("(p + [%d]) address : %d\n", i, (p + i) ); | |
printf("*(p + [%d]) value : %d\n", i, *(p + i) ); | |
} | |
return 0; | |
} |