九日集训day3数组_pt1|心猿意马

本文详细介绍了C语言中的数组概念,包括顺序存储结构、数组长度、容量、索引,以及在函数传参中的不同形式。讨论了数组溢出、数据类型和如何确保函数不修改传入数组。还展示了C++中数组处理的现代特性,如模板和std::array,以及sizeof运算符的使用规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

九日集训day3数组_pt1 心猿意马优快云

数组知识快读盘点

以下是针对数组知识的Markdown文本的优化版本,旨在提高可读性和信息的清晰度:

基础知识:数组

顺序存储结构

数组是一种顺序存储结构,可用于存储相同类型的多个元素。数组可以完全初始化,也可以部分初始化,如下所示:

  • 完全未初始化:int a[8];
  • 完全初始化:int a[5] = {1, 2, 3, 4, 5};
  • 部分初始化:int a[10] = {1, 2, 3, 4, 5};
  • 自动推断长度:int a[] = {1, 2, 3, 4, 5};(长度为5)
长度、容量和索引
  • 长度:数组当前包含的元素数量。
  • 容量:数组最大能存储的元素数量,定义时确定。
  • 索引:数组元素的索引从0开始。
注意事项
  • 数组溢出:数组索引超出其定义范围会导致运行时错误,可能引发不可预料的问题,因此必须避免。
  • 数据类型:数组可以存储不同的数据类型,包括但不限于:
    • int:32位整型
    • float:单精度浮点型
    • double:双精度浮点型
    • char:字符型
    • long long:64位整型
    • short:16位短整型

数组的函数传参

  1. add(int num[20]):此声明方式明确数组的大小为20,但在传递给函数时,这种大小信息并不强制要求数组必须有20个元素,它主要用于文档上的指示,说明期望的数组大小。

  2. add(int num[]):此声明没有指定数组大小,这在函数内部意味着num仅是一个指向整型的指针。

  3. add(int *num):此方式直接将数组作为指针传递,这是更明确地表明数组被视为一个指针。

本质分析

所有这三种方式的本质都是通过指针传递数组的首地址。C语言中数组名本质上是一个指向数组第一个元素的指针。因此,无论哪种形式,函数内部接收到的都是指向原始数组的指针,而非数组的复制。这意味着在函数内对数组元素的任何修改都会影响到原始数组。

能否改变原数组?

由于所有这三种传递方式本质上都是传递数组的地址,所以在函数内对数组的修改都会反映到原数组上。

示例代码
#include <stdio.h>

// 使用具体数组大小
void addSize(int num[20]) {
    int sum = 0;
    for (int i = 0; i < 10; i++) {  // 只累加前10个元素
        sum += num[i];
    }
    printf("通过指定大小累加的结果:%d\n", sum);
}

// 使用不确定大小的数组
void add(int num[]) {
    int sum = 0;
    for (int i = 0; i < 10; i++) {  // 只累加前10个元素
        sum += num[i];
    }
    printf("通过未指定大小累加的结果:%d\n", sum);
}

// 使用指针
void addPtr(int *num) {
    int sum = 0;
    for (int i = 0; i < 10; i++) {  // 只累加前10个元素
        sum += num[i];
    }
    printf("通过指针累加的结果:%d\n", sum);
}

int main() {
    int numbers[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  // 只初始化前10个元素
    
    addSize(numbers);
    add(numbers);
    addPtr(numbers);
    
    return 0;
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

演示三种传参方式能否影响到原数组:

#include <stdio.h>

// 使用具体数组大小
void modifySize(int num[20]) {
    for (int i = 0; i < 10; i++) {  // 修改前10个元素
        num[i] += 5;  // 每个元素增加5
    }
}

// 使用不确定大小的数组
void modify(int num[]) {
    for (int i = 0; i < 10; i++) {  // 修改前10个元素
        num[i] += 10;  // 每个元素增加10
    }
}

// 使用指针
void modifyPtr(int *num) {
    for (int i = 0; i < 10; i++) {  // 修改前10个元素
        num[i] += 15;  // 每个元素增加15
    }
}

void printArray(int num[], int size) {
    for (int i = 0; i < size; i++) {
        printf("%d ", num[i]);
    }
    printf("\n");
}

int main() {
    int numbers[20] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};  // 只初始化前10个元素
    
    printf("原始数组: ");
    printArray(numbers, 20);
    
    modifySize(numbers);
    printf("使用具体大小修改后: ");
    printArray(numbers, 20);
    
    modify(numbers);
    printf("使用未指定大小修改后: ");
    printArray(numbers, 20);
    
    modifyPtr(numbers);
    printf("使用指针修改后: ");
    printArray(numbers, 20);
    
    return 0;
}

演示结果:
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
tips:为什么后面都打印的是0?明明没有进行初始化啊?
在C语言中,当你声明一个局部数组而没有完全初始化它时,未初始化的元素的值是未定义的。这意味着它们可能包含任何值,通常是内存中已存在的值。然而,在大多数现代编译器中,当数组被部分初始化时,未明确初始化的元素通常会默认初始化为0。这是为了提供一定的安全性和可预测性,但这种行为并非C标准所保证的。

在你的示例代码中,你初始化了数组 numbers 的前10个元素,后10个元素没有被显式初始化。由于在很多实现中,局部数组的未初始化元素会默认为0,这就是为什么这些元素在打印时显示为0的原因。然而,依赖于此行为可能不是一个好的编程实践,因为它依赖于具体的编译器行为,可能在不同的编译器或设置中得到不同的结果。

在C语言中,确保一个函数不修改传入的数组可以通过两种主要方法实现:
使用 const 限定符

使用 const 关键字是确保函数不修改传入数组的标准方法。这个关键字可以应用于函数的参数,以表明该参数不应被修改。例如:

void processArray(const int *array, int size) {
    // 这里尝试修改 array 的内容将会导致编译错误
    for (int i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
}

在这个例子中,const int *array 表示 array 是一个指向 int 的指针,其中的 int 值不能被修改。如果函数试图修改 array 指向的内容,比如通过 array[i] = value;,编译器将报错,因为这违反了 const 限定。

复制数组

另一种方法是在函数内部创建数组的副本,然后对副本进行操作,这样原始数组的值不会被改变:

void processArray(int array[], int size) {
    int localArray[20]; // 假设知道数组不会超过20个元素
    for (int i = 0; i < size; i++) {
        localArray[i] = array[i];  // 复制数组元素
    }

    // 在 localArray 上进行操作
}

在这种情况下,即使 processArray 函数修改了 localArray,原始的 array 也不会受到影响,因为仅仅修改了它的副本。

注意

在C++中,你提到的“引用”也是一种传递参数的方式,它可以保证引用的对象不被修改(如果使用 const)。例如:

void processArray(const int (&array)[20]) {
    // 这里无法修改 array 的内容
}

这种方式在C++中非常有用,它通过引用传递数组,并通过 const 保证不修改数组。但请注意,C语言中没有引用的概念;引用是C++特有的。

如何自动确定数组的大小?

在C语言和C++中,数组一旦传递给函数,就会退化成指针,失去其长度信息。这意味着无法直接在函数中确定数组的长度。但是,我们可以使用几种技巧来解决这个问题,具体方法取决于你的编程环境是C还是C++。

C语言

在C语言中,通常需要手动传递数组的长度作为一个额外的参数给函数。这是最常见的做法,因为C语言本身没有内建的方式来检查数组的长度。

#include <stdio.h>

void printArrayLength(int *array, int length) {
    printf("Length of the integer array is: %d\n", length);
}

void printCharArrayLength(char *array, int length) {
    printf("Length of the char array is: %d\n", length);
}

int main() {
    int intArray[] = {1, 2, 3, 4, 5};
    char charArray[] = "Hello";

    // 注意,对于charArray,strlen可以用来获取字符串长度,不包括null字符
    printArrayLength(intArray, sizeof(intArray) / sizeof(intArray[0]));
    printCharArrayLength(charArray, sizeof(charArray) - 1);

    return 0;
}

C++

C++ 提供了一些更灵活的方式来处理这个问题,特别是模板和 std::array。使用模板,你可以创建一个函数,它可以推导数组的长度。

使用模板
#include <iostream>

template<typename T, size_t N>
void printArrayLength(T(&array)[N]) {
    std::cout << "Length of the array is: " << N << std::endl;
}

int main() {
    int intArray[] = {1, 2, 3, 4, 5};
    char charArray[] = "Hello";

    printArrayLength(intArray);
    printArrayLength(charArray);  // 这里会包括null终止符

    return 0;
}
使用 std::array

如果你使用C++11或更高版本,可以使用 std::array,它保留了数组的长度信息。

#include <iostream>
#include <array>

int main() {
    std::array<int, 5> intArray = {1, 2, 3, 4, 5};
    std::array<char, 6> charArray = {'H', 'e', 'l', 'l', 'o', '\0'};

    std::cout << "Length of the integer array is: " << intArray.size() << std::endl;
    std::cout << "Length of the char array is: " << charArray.size() - 1 << std::endl;

    return 0;
}

在这些示例中,使用C++的模板和 std::array 可以使代码更加安全和易于管理,同时还提供了数组长度的自动推导,这是在纯C语言中无法实现的。对于C++,优先选择使用这些现代特性,特别是当安全和易用性是关键考虑因素时。

sizeof的注意

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
这里我们稍微修改了代码让大家知道为什么不能这么写sizeof

#include <stdio.h>

void printArrayLength(int *array, int length) {
    printf("Length of the integer array is: %d\n", sizeof array);
}

void printCharArrayLength(char *array, int length) {
    printf("Length of the char array is: %d\n", sizeof array);
}

int main() {
    int intArray[] = {1, 2, 3, 4, 5};
    char charArray[] = "Hello";

    // 注意,对于charArray,strlen可以用来获取字符串长度,不包括null字符
    printArrayLength(intArray, sizeof(intArray) / sizeof(intArray[0]));
    printCharArrayLength(charArray, sizeof(charArray) - 1);

    return 0;
}

打印出来为什么是8?
因为这里打印的是array指针的大小,通常为8个字节。即使把int *array换成int *array[]都是一样的,这点要注意。

在主函数里面使用的sizeof

#include <stdio.h>

void printArrayLength(int *array, int length) {
    printf("Length of the integer array is: %d\n", length);
}

void printCharArrayLength(char *array, int length) {
    printf("Length of the char array is: %d\n", length);
}

int main() {
    int intArray[] = {1, 2, 3, 4, 5};
    char charArray[] = "Hello";

    // 注意,对于charArray,strlen可以用来获取字符串长度,不包括null字符
    printArrayLength(intArray, sizeof(intArray) / sizeof(intArray[0]));
    printCharArrayLength(charArray, sizeof(charArray) - 1);

    return 0;
}

为什么这里正确的打印方法是sizeof(intArray) / sizeof(intArray[0])?
在C语言中,sizeof 运算符用于获取内存中数据类型或数据结构所占的字节数。当 sizeof 用于数组时,它返回整个数组所占用的字节数。要获取数组中元素的数量,需要将数组的总字节大小除以单个元素的字节大小。

解释如下:

数组的总大小
  • sizeof(intArray) 返回整个 intArray 的大小(以字节为单位)。因为 intArray 是一个由5个整数组成的数组,而每个整数通常在C语言中占用4字节(这取决于编译器和平台),所以整个数组的大小通常是 5 * 4 = 20 字节。
单个元素的大小
  • sizeof(intArray[0]) 返回数组中单个元素的大小。在这个例子中,intArray[0]intArray 中的第一个整数,所以 sizeof(intArray[0]) 是4字节。
计算数组长度
  • 通过 sizeof(intArray) / sizeof(intArray[0]),你实际上是在计算 20 / 4 = 5,这正是数组中元素的数量。

这种方法可以用于任何类型的数组(不仅仅是整数)来准确地计算数组中的元素数量,只要你知道数组的总大小和单个元素的大小。这是在C语言中处理数组长度的常见技巧,特别是在数组作为参数传递给函数时,因为传递的数组会退化为指针,失去其原有的大小信息。

主函数 & 传参的数组名有什么区别让 sizeof 的运用都不同了?

在C语言中,当你在函数外部声明并初始化一个数组,如 int intArray[] = {1, 2, 3, 4, 5};intArray 在这个上下文中确实是一个数组,不是一个指针。因此,使用 sizeof 运算符于 intArray 时,它计算的是整个数组的大小,而不是指针的大小。

这里的关键在于 intArray 的上下文和用法。在声明时它是一个具有完整尺寸信息的数组。这意味着编译器知道这个数组包含多少个元素,以及每个元素的大小。因此,sizeof(intArray) 会返回所有这些整数元素占用的总字节数。

指针的情况

当数组作为参数传递给函数时,数组名称(如 intArray)会退化为指向数组首元素的指针。在函数内部,这个“数组”实际上已经是一个指针了,因此如果在函数内部对同名参数使用 sizeof,结果将是指针的大小,而不是原始数组的总大小。

例如,考虑以下函数定义:

void exampleFunction(int arr[]) {
    // 这里 sizeof(arr) 将返回指针的大小,而非数组总大小。
}

如果在 main 函数或其它任何数组被定义为数组的地方使用 sizeof(intArray),你得到的是整个数组的大小。但在如上的函数内部使用 sizeof(arr),你会得到的是指向 int 的指针的大小(通常是4或8字节,依据平台和编译器的不同)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值