第四周

一维数组

一维数组的定义和初始化

数组属于一种构造数据类型,由一定数量的相同类型的元素构成。

  • 一维数组定义的语法格式:

    <数据类型> <数组名称>[<大小>] = {<元素1>, <元素2>, ..., <元素N>};

    其中:

    1. <数据类型> 指定数组中元素的数据类型,可以是基本类型(如 int、float、char 等)或自定义类型。
    2. <数组名称> 是数组的标识符,用于在程序中引用该数组。
    3. <大小> 指定数组的大小,即数组中元素的个数。
    4. {<元素1>, <元素2>, …, <元素N>} 是可选的初始化列表,用于初始化数组中的元素。

    数组定义举例:

    // 定义一个包含 5个整数的数组
    int numbers[5] = {1, 2, 3, 4, 5};
    // 定义一个包含 4个字符的数组
    char characters[4] = {'A', 'B', 'C', 'D'};
    // 定义一个包含 6个浮点数的数组
    float values[6];
  • 一维数组的初始化

    创建test.c文件,编辑以下内容,可以通过IDE的调试功能观察数组的初始化:

    #include <stdio.h>
    
    int main(void)
    {
        int number[5] = {1, 2, 3, 4, 5};
        //定义一个包含4个字符的数组并对前三个元素进行初始化
        char characters[4] = {'A', 'B', 'C'};
        //定义一个包含6个浮点数的数组并对第一个元素进行初始化
        float values[6] = {1.0};
    
        return 0;
    }

一维数组的引用

4.第四周-2023-06-24-00-05-18

创建test.c文件,编辑以下代码:

#include <stdio.h>

int main(void)
{
    int number[5] = {1, 2, 3, 4, 5};

    printf("第一个元素是:%d\n", number[0]);    //输出:第一个元素是:1
    printf("第二个元素是:%d\n", number[1]);    //输出:第二个元素是:2
    printf("第三个元素是:%d\n", number[2]);    //输出:第三个元素是:3

    return 0;
}

二维数组

二维数组是由多个一维数组组成的数据结构,在C语言中可以使用以下方式进行定义和初始化:

数据类型 数组名[行数][列数];

4.第四周-2023-06-24-00-40-55

创建test.c文件,编辑以下代码:

#include <stdio.h>

int main() {
    // 定义一个 3x4 的整数二维数组
    int number[3][4];

    // 初始化二维数组的元素
    number[0][0] = 1;
    number[0][1] = 2;
    number[0][2] = 3;
    number[0][3] = 4;

    //在定义时初始化数组
    int num[3][4] = {
    {1, 2, 3, 4},
    {5, 6, 7, 8},
    {9, 10, 11, 12}
    };


    // 打印输出二维数组的元素
    printf("number:\n");
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 4; j++) {
            printf("%d ", number[i][j]);
        }
        printf("\n");
    }

    return 0;
}

字符串与字符数组

创建test.c文件,编辑以下代码:

#include <stdio.h>
#include <string.h>
int main(void)
{
    /*字符数组赋初值*/
    char cArr[] = {'I','L','O','V','E','C'};
    /*字符串赋初值
    编译时会自动在末尾增加一个 null 字符*/
    char sArr[] = "ILOVEC";
    /*用sizeof()求长度*/
    printf("cArr的长度=%d\n", sizeof(cArr));    //输出:cArr的长度=6
    printf("sArr的长度=%d\n", sizeof(sArr));    //输出:sArr的长度=7
    /*用strlen()求长度*/
    printf("cArr的长度=%d\n", strlen(cArr));    //输出:cArr的长度=12
    printf("sArr的长度=%d\n", strlen(sArr));    //输出:sArr的长度=6
    /*用printf的%s打印内容*/
    printf("cArr的内容=%s\n", cArr);            //输出:cArr的内容=ILOVECILOVEC
    printf("sArr的内容=%s\n", sArr);            //输出:sArr的内容=ILOVEC
    return 0;
}
  • 对于字符数组,其长度是固定的,其中任何一个数组元素都可以为 null 字符。因此,字符数组不一定是字符串。
  • 对于字符串,它必须以 null 结尾,其后的字符不属于该字符串。字符串一定是字符数组,它是最后一个字符为 null 字符的字符数组。

函数的定义和调用

函数定义的一般格式:

返回值类型 函数名(参数列表) {
    // 函数体
    // 执行特定的功能代码
    // 可能包含 return 语句用于返回结果
}

创建test.c文件,编辑以下代码:

#include <stdio.h>

// 用户自定义函数,计算两个整数的和
int sum(int a, int b) {
    int result = a + b;
    return result;
}

int main() {
    int num1 = 5;
    int num2 = 7;

    // 调用自定义函数
    int result = sum(num1, num2);
    
    printf("The sum is: %d\n", result);

    return 0;
}

需要注意以下几点:

  1. 返回值类型:指定函数返回的结果的类型,可以是整数类型、浮点类型、字符类型或指针类型等。
  2. 函数名:用于标识函数的名称,在调用函数时使用该名称。
  3. 参数列表:列出函数接受的参数类型和参数名称,多个参数之间用逗号分隔。
  4. 函数体:包含了执行特定功能的代码,可以是一条或多条语句。
  5. 返回值:使用return语句将结果返回给调用者。返回值类型必须与函数定义中的返回值类型匹配。

函数声明的用法:

#include <stdio.h>

// 函数声明
int sum(int a, int b);

int main() {
    int num1 = 5;
    int num2 = 7;

    // 调用自定义函数
    int result = sum(num1, num2);
    
    printf("The sum is: %d\n", result);

    return 0;
}

// 函数定义
int sum(int a, int b) {
    int result = a + b;
    return result;
}

函数的值传递

在 C 语言中,函数参数的传递方式是值传递(pass-by-value)。这意味着在函数调用时,实际参数的值会被复制给形式参数(函数定义中的参数),并在函数内部使用。因此,函数内部对形式参数的修改不会影响到实际参数的值。

创建test.c文件,编辑以下代码:

#include <stdio.h>

void modifyValue(int x) {
    x = 10;  // 修改形式参数 x 的值
}

int main() {
    int num = 5;

    printf("Before function call: %d\n", num);  //输出结果:Before function call: 5

    modifyValue(num);  // 调用函数,传递实际参数 num

    printf("After function call: %d\n", num);   //输出结果:After function call: 5

    return 0;
}

需要注意的是,如果实际参数是指针类型,函数可以通过指针间接地修改实际参数所指向的值。这是因为指针本身也是一个值,通过复制指针的值,函数可以访问和修改指针所指向的内存。但是,这并不改变值传递的本质,只是通过指针来间接地修改了实际参数的值。

#include <stdio.h>

void modifyValue(int *ptr) {
    *ptr = 10;  // 通过指针修改实际参数的值
}

int main() {
    int num = 5;

    printf("Before function call: %d\n", num);

    modifyValue(&num);  // 传递实际参数的地址作为指针参数

    printf("After function call: %d\n", num);

    return 0;
}

递归调用

在 C 语言中,递归调用是指一个函数直接或间接地调用自身。递归调用通常用于解决可以分解为相同问题的子问题的情况,每次递归调用都在更小的范围内解决问题,直到达到终止条件。

下面是一个示例,演示了在 C 语言中使用递归调用计算斐波那契数列的第 n 个数字(斐波那契数列前11位:1,1,2,3,5,8,13,21,34,55,89):

#include <stdio.h>

int fibonacci(int n) {
    // 终止条件
    if (n == 0) {
        return 0;
    } else if (n == 1) {
        return 1;
    }
  
    // 递归调用
    return fibonacci(n - 1) + fibonacci(n - 2);
}

int main() {
    int n = 10;
    int result = fibonacci(n);

    printf("The %dth Fibonacci number is: %d\n", n, result);

    return 0;
}

全局变量和局部变量

在C语言中,局部变量和全局变量是两种不同的变量类型,它们具有不同的作用域和生存周期。

  • 局部变量

    1. 局部变量是在函数内部声明的变量,它只在函数的作用域内可见。
    2. 局部变量的作用域仅限于声明它的函数内部,函数执行结束后,局部变量将被销毁。
    3. 局部变量必须在使用之前先进行声明。
    4. 局部变量的生命周期随着函数的调用和执行而开始和结束。

    示例代码:

    # include <stdio.h>
    
    void foo() {
        int x = 10;  // 局部变量 x
        printf("Inside foo: %d\n", x);
    }
    
    int main() {
        foo();
        // printf("%d\n", x);  // 错误,无法访问 foo 函数内的局部变量 x
    
        return 0;
    }
  • 全局变量

    1. 全局变量是在函数外部声明的变量,它可以在整个程序的任何地方访问。
    2. 全局变量的作用域从声明开始,延伸到文件的末尾,可以在程序的任何地方使用和修改它。
    3. 全局变量在程序启动时创建,在程序结束时销毁。
    4. 全局变量可以在任何函数内部进行访问,但需要通过关键字 extern 进行声明。

    示例代码:

    # include <stdio.h>
    
    int globalVar = 20;  // 全局变量
    
    void foo() {
        printf("Inside foo: %d\n", globalVar);
    }
    
    int main() {
        foo();
        printf("Inside main: %d\n", globalVar);
    
        return 0;
    }

需要注意的是,全局变量的使用应谨慎,因为全局变量的可见性和可修改性可能会导致程序的可维护性和可理解性下降。一般来说,应该尽量避免过度使用全局变量,而是优先使用局部变量来限制变量的作用范围,以提高代码的可读性和可维护性。