数组的定义与传递

本文探讨了C语言中数组的定义,包括栈区与全局区的区别,以及一维数组作为函数参数时的行为。重点分析了数组传参时的地址传递,解释了指针偏移量的变化,并讨论了二维数组的传递方式。

数组

数组的定义
#include <stdio.h>
#define MAX_N 10000000

int main() {
    int arr[MAX_N + 5];
    printf("%d\n", arr[0]);
    return 0;
}

函数内部定义数组 : 在栈区开辟内存, 栈区的大小只有8MB;因此函数内部的数组大小最大只能定义大概200W个整型的大小;不然就爆栈

函数外部定义数组 : 在全局区上申请内存, 且数组每一位自动初始化为0{空};

#include <stdio.h>
#define MAX_N 100

int arr[MAX_N + 5];
int main() {
    printf("arr = %p , arr[0] = %p\n", arr, &arr[0]);
    //arr的地址和arr[0]的地址相同
    for (int i = 0; i < MAX_N; i++) {
        scanf("%d", arr + i);
        //等价于scanf("%d", &arr[i]);
    }
 	
    printf("%d\n", arr[0]);
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V4AoGPVp-1610715942300)(D:\Mark文档_date\图库\image-20210115141349241.png)]

int arr[MAX_N + 5];
char *p = (char *)arr;
printf("arr = %p,arr[0] = %p\n", arr, &arr[0]);
printf("arr + 1 = %p\n", arr +1);
printf("p = %p, p + 1 = %p\n", p, p+1);
  • 输出结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FDy7FQoT-1610715942302)(D:\Mark文档_date\图库\image-20210115141926917.png)]

分析得知 : 不同类型的指针进行跳跃的字节数, 和类型所占字节数相关, 但指针 arr从整型指针强转为char型指针时偏移的量发生变化; 由 偏移4 字节变为了偏移1字节;

一维数组作为函数参数
#include <stdio.h>
void func(int *p) {
    printf("p[0] = %d\n", p[0]);
    return ;
} 
int main() {
    int arr[1000] = {0};
    arr[0] = 1;
    func(arr);
    return 0;
}

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cej6yu9N-1610715942304)(D:\Mark文档_date\图库\image-20210115142626396.png)]

我们这里传递的是数组的地址,因此在函数内部进行修改数组,外部也一定会发生改变;

#include <stdio.h>
void func(int *p) {
    printf("p[0] = %d\n", p[0]);
    p[0] = 123;
    return ;
} 
int main() {
    int arr[1000] = {0};
    arr[0] = 1;
    func(arr);
    printf("main : arr[0] = %d\n", arr[0]);
    return 0;
}
  • 运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLRhaDIt-1610715942306)(D:\Mark文档_date\图库\image-20210115143258815.png)]

*而且在函数中void func(int p)我们传递的p实际上是就是指向整型指针变量;

#include <stdio.h>
void func(int *p) {
    printf("p[0] = %d\n", p[0]);
    p[0] = 123;
    printf("sizeof(p) = lu\n", sizeof(p));//这里打印p的大小,因为sizeof函数的返回值为无符号长整型,我么用%lu;
    return ;
} 
int main() {
    int arr[105] = {0};
    arr[0] = 1;
    func(arr);
    printf("sizeof(arr) =%lu\n", sizeof(arr));//这里我们打印数组的大小;
    return 0;
}
  • 输出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZNCbuReD-1610715942309)(D:\Mark文档_date\图库\image-20210115144049490.png)]

我们可以明显的发现p就是一个针指变量; 因为 p 的表现形式和arr是一样的, 因此我们将arr的地址赋值给指针p;

#include <stdio.h>
void func(int *p) {
    printf("p[0] = %d\n", p[0]);
    p[0] = 123;
    printf("p = %p, p + 1 = %p\n", p ,p+1);
    printf("sizeof(p) = lu\n", sizeof(p));//这里打印p的大小,因为sizeof函数的返回值为无符号长整型,我么用%lu;
    return ;
} 
int main() {
    int arr[105] = {0};
    arr[0] = 1;
    char *p = (char *)arr;
	printf("arr = %p,arr[0] = %p\n", arr, &arr[0]);
	printf("arr + 1 = %p\n", arr +1);
    func(arr);
    printf("sizeof(arr) =%lu\n", sizeof(arr));//这里我们打印数组的大小;
    return 0;
}
  • 运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IoMAIwhI-1610715942310)(D:\Mark文档_date\图库\image-20210115144651147.png)]

p+1 的偏移量和arr + 1 是一样的, 表现形式一样; 因此我们可以这样去传参;

高维数组传参
  • 猜想尝试, 能用 **p 指针传递二维数组吗, 我们来k一k,首先看他们的表现形式

    #include <stdio.h>
    #define MAX_N 100
    
    int main() {
        int arr[MAX_N + 5][3];
        int **p;
        printf("arr = %p, arr[0] = %p\n", arr, &arr[0]);
        printf("arr + 1 = %p\n", arr+1);
        printf("p = %p, p + 1 = %p\n",p , p+1);
        return 0;
    }
    
  • 运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0c8WlbiY-1610715942310)(D:\Mark文档_date\图库\image-20210115150256273.png)]

arr +1偏移了12字节, 而p+1 偏移了8字节, int **p (是一个指针变量, 变量p中存放的是int *类型的数据)而在 64 位操作系统中一个指针变量它的大小是8字节; 因此 p+1 会偏移 8字节;

  • 那我们如何传递二维数组的参数呢?

    #include <stdio.h>
    #define MAX_N 100
    
    void func(int (*p)[3]) {//传递一个指向(3个int长度数组的)指针;
        printf("p = %p, p + 1 = %p\n", p, p+1);
        printf("sizeof(p) = %lu\n", sizeof(p));
        return ;
    }
    int main() {
        int arr[MAX_N + 5][3];
        printf("arr = %p, arr[0] = %p\n", arr, &arr[0]);
        printf("arr + 1 = %p\n", arr+1);
        func(arr);
        printf("sizeof(arr) = %lu\n", sizeof(arr));
        return 0;
    }
    

    运行结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fM85imHj-1610715942311)(D:\Mark文档_date\图库\image-20210115151328861.png)]

  • 传递二维数组的方法二

#include <stdio.h>
#define MAX_N 100

void func(int p[][3]) {//传递一个数组p[][3],二维长度必须标明;
    printf("p = %p, p + 1 = %p\n", p, p+1);
    //printf("sizeof(p) = %lu\n", sizeof(p));注释这行,p的一维长度被我们省略了
    return ;
}
int main() {
    int arr[MAX_N + 5][3];
    printf("arr = %p, arr[0] = %p\n", arr, &arr[0]);
    printf("arr + 1 = %p\n", arr+1);
    func(arr);
    printf("sizeof(arr) = %lu\n", sizeof(arr));
    return 0;
}

注意我们传递的参数表现形式一定要是一样的

### 数组传递的概念实现 #### C语言中的数组传递 在C语言中,数组通常以指针的形式进行传递。当我们将数组作为参数传递函数时,实际上传递的是指向数组第一个元素的指针[^1]。这意味着,在函数内部对数组的操作会直接影响原始数组的内容。 以下是通过引用传递数组并对其进行排序的一个例子: ```c #include <stdio.h> void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { // 交换两个元素的位置 int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } int main() { int data[] = {64, 34, 25, 12, 22, 11, 90}; int size = sizeof(data) / sizeof(data[0]); printf("未排序数组:\n"); for (int i = 0; i < size; i++) { printf("%d ", data[i]); } bubbleSort(data, size); printf("\n已排序数组:\n"); for (int i = 0; i < size; i++) { printf("%d ", data[i]); } return 0; } ``` 此程序展示了如何利用冒泡排序算法对整型数组进行排序[^1]。 #### Java中的数组传递 在Java中,数组可以通过值或引用的方式传递给方法。如果仅修改数组内的元素,则原数组会被改变;但如果重新分配一个新的数组对象,则不会影响原来的数组对象[^2]。 下面是一个演示如何创建新数组并将它返回的例子: ```java public class ArrayPassingExample { public static void modifyArray(int[] array) { array[0] = 99; // 修改原有数组的第一个元素 array = new int[]{88, 77}; // 创建新的局部变量array,不影响调用者处的数组 } public static void main(String[] args) { int[] myArray = {1, 2, 3}; System.out.println("Before modification:"); for (int value : myArray) { System.out.print(value + " "); } modifyArray(myArray); System.out.println("\nAfter attempted modification:"); for (int value : myArray) { System.out.print(value + " "); // 输出应显示首项已被改为99 } } } ``` 这段代码说明了即使在`modifyArray()`方法里改变了`array`所指向的对象,这并不会影响到`main()`里的`myArray`对象[^2]。 #### Linux Shell中的数组传递 对于Shell脚本而言,可以使用特殊字符 `$*` 和 `$@` 来处理命令行参数列表。其中的区别在于它们对待多个参数的行为方式有所不同:`$*` 将所有的参数视为单一字符串,而 `$@` 则保持各参数独立性[^4]。 示例如下: ```bash #!/bin/bash function print_args { echo "\$*: '$*' -> '$*'" echo "\$@: '\$@' -> '$@'" } print_args one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty ``` 以上脚本定义了一个接受任意数量参数的功能,并分别打印出这些参数是如何被解释器看待的。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值