主要回顾 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;
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Jalen Chu 微信支付

微信支付

Jalen Chu 支付宝

支付宝

Jalen Chu 公众号

公众号