复合型数据结构:C数组

本文详细探讨了C语言中数组的特例——字符串,通过字符数组和字符指针两种方式定义字符串,并分析它们的区别。此外,还介绍了静态数组、动态数组的概念,以及指针数组和数组指针的应用,包括二维数组和指针数组的接收方式。内容涵盖测试代码和栈帧结构分析。

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

1 数组的特例:字符串

在C语言中,定义一个字符串样式的数组,有如下两种方式:

char arr[] = "abcdefg";
char *str = "abcdefg";

这两种方式有什么区别呢?别看它们表面上都差不多,其实差远了!

1.1 字符数组定义字符串——从一而终

这里的数组名 arr:实际上是个变种的“指针常量”
(1)常量说明了“绑定关系”不能变,这种定义字符串的方式,会在栈帧里面存放“abcdefg\0”这一个字符数组实体,arr 在函数体的整个生命周期里面不能再绑定其他的东西!直到这个函数体的消亡,一起被销毁;
(2)“变种”有3个含义:
① 共享房子的大小:arr的大小,将等于"abcdefg\0"的大小
② 共享房子的位置:arr的地址,将等于战阵中"abcdefg\0"的首地址
③ 相敬如宾:arr这个指针不能随便去"abcdefg\0"里面随便乱指,只能通过arr[0],arr[1]……这种固定的方式去访问“abcdefg\0”中的内容

1.2 字符指针定义字符串——登徒浪子

这里的指针 char *str:是一个指针量,它就是一个登徒浪子!
(1)变量说明了“绑定关系”可以随时变!str在整个函数体的生命周期中,不一定非要绑定"abcdefg\0"这一个字符串常量,看它不顺眼了,可以改!
(2)“登徒浪子”是相对独立自主的!
① str 拥有自己独立的大小(就是指针的大小,与机器字长有关),而与字符串常量"abcdefg\0"的大小无关;
② str 拥有自己独立的地址,在栈帧之中占据一席地位,独立地分配了栈帧中的字节!
③ str 特别喜欢指指点点,可以使用str++, str–这样的方式,在 “abcdefg\0” 里面指来指去!

1.3 测试代码

#include <stdio.h>
int main(int argc, char *argv[]){
    char arr[] = "abcdefh";
    char *str = "abcdefh";

    printf("argv = 0x%x\r\n", &argv);
    printf("argc = 0x%x\r\n", &argc);

    printf("adress of arr = 0x%x\r\n", &arr);
    printf("adress of char *str = 0x%x\r\n", &str);

    printf("adress of arr[0] = 0x%x\r\n", &arr[0]);
    printf("adress of str[0] = 0x%x\r\n", &str[0]);
    printf("adress of str[1] = 0x%x\r\n", &str[1]);

    printf("arr[1] = \'%c\'\r\n", *(arr + 1));
    printf("arr[0] = \'%c\'\r\n", *arr);

    printf("*str++ = \'%c\'\r\n", *str++);
    printf("now, \"str\" points to = \'%c\'\r\n", *str);
    printf("str-- = \'%c\'\r\n", *str--);
    printf("now, \"str\" points to \'%c\'\r\n", *str);

    return 0;
}

在这里插入图片描述

1.4 栈帧结构

在这里插入图片描述

2 数组

类型说明
静态数组数组的大小不能变
动态数组数组的大小可以动态改变

2.1 静态数组

2.1.1 数组测试代码

#include <stdio.h>

int main(int argc, char *argv[]){

    int i = 10;
    int j = 20;

    int array[4] = {
        1, 2, 3, 4
    };

    int *p = array;
    
    printf("argv = 0x%x\r\n", &argv);
    printf("argc = 0x%x\r\n", &argc);
    printf("int variable address = 0x%x\r\n", &i);
    printf("int variable address = 0x%x\r\n", &j);

    printf("array 0 address = 0x%x\r\n", &array[0]);
    printf("array 1 address = 0x%x\r\n", &array[1]);
    printf("array 2 address = 0x%x\r\n", &array[2]);
    printf("array 3 address = 0x%x\r\n", &array[3]);
    printf("pointer address = 0x%x\r\n", &p);

    printf("int size %d", sizeof(int));

    return 0;
}

在这里插入图片描述

2.1.2 栈帧结构

在这里插入图片描述

2.2 动态数组

C99 以上是支持“动态数组”的,可以使用如下语句:

int arr[i];

这个 i 是个变量,C99以下不能这样玩,需要使用 malloc() 手动实现动态数组,使用 realloc() 可以对数组长度动态地进行调整,实现方法如下:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define     ARR_SIZE        8
int main(int argc, char *argv[]){
   	int *dynamic_arr = (int *)malloc(ARR_SIZE * sizeof(int)); // Creating a dynamic array
    assert(dynamic_arr != NULL);

    for(int i = 0; i < ARR_SIZE; i ++){ // Printing the dynamic array
        printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
    }

    for(int i = 0; i < ARR_SIZE; i++){ // Initializing the dynamic array
        dynamic_arr[i] = 0;
    }

    for(int i = 0; i < ARR_SIZE; i ++){ // Printing the dynamic array
        printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
    }
    /******** Adjusting the length of the dynamic array ********/
    dynamic_arr = (int *)realloc(dynamic_arr, 16 * sizeof(int)); 

    for(int i = 0; i < 16; i ++){ // Printing the new dynamic array
        printf("dynamic_arr[%d] = %d \r\n", i, dynamic_arr[i]);
    }

    free(dynamic_arr); // Destroy the dynamic array

    return 0;
}

在这里插入图片描述

3 指针数组和数组指针

注意:“各种括号” 的优先级比 “*” 高!

类别示例说明应用
指针数组char * s t r [ 8 ] \color{red}str[8] str[8]下标[8] 先结合,是数组,数组里每个单元放一个指针函数入参,接收“字符串数组”
数组指针int ( ∗ p A r r \color{red}*pArr pArr)[4]括号() 先结合,是指针,指针指向一个int a[4] 样式数组函数入参,接收“二维数组”

3.1 用数组指针接收“二维数组”

int print_2Array(int (*pArr)[4], int len){
    for(int i = 0; i < len; i++){
        for(int j = 0; j < 4; j++){
            printf("|%-4d", pArr[i][j]);
        }
        printf("|\r\n");
    }
}

3.2 用二级指针接收“指针数组”

int print_strings(char **str, int len){
    for(int i = 0; i < len; i++){
        printf("|%-16s|\r\n", str[i]); // 1-level deference 
    }
}

3.3 测试例程

#include <stdio.h>
int main(int argc, char *argv[]){
    char *str[8] = {
        "Alice",
        "Danny",
        "Jenny",
        "Red",
        "Xiaoming",
        "Alex",
        "Angel",
        "Jack"
    };

    int arr[6][4] = {
        {1, 2, 3, 4},
        {5, 6, 7, 8},
        {9, 0, 1, 2},
        {3, 4, 5, 6},
        {7, 8, 9, 0},
        {1, 2, 3, 4},
    };

    int (*pArr)[4] = arr;

    print_strings(str, sizeof(str) / sizeof(void *));

    print_2Array(pArr, sizeof(arr) / sizeof(arr[0]));
    
	printf("size of [arr] is %d bytes\r\n", sizeof(arr));
    printf("size of [pArr] is %d bytes\r\n", sizeof(pArr));
	
	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值