• C专家编程 第10章 再论指针 10.3 在锯齿状数组上使用指针


    在锯齿状数组上使用指针
    Iliffe向量是一种旧式的编译器编写技巧,最初用于Algol-60。它们原先用于提高数组访问的速度,以及在内存有限的机器中只存储数组的部分数据。在现代的系统中,这两个用途都已毫无必要,但Iliffe向量在另外两个方面仍然具有价值:存储各行长度不一的表以及在一个函数调用中传递一个字符串数组。如果需要存储50个字符串,每个字符串的最大长度可以达到255个字符,可以声明下面的二维数组:
    char carrot[50][256];
    它声明了50个字符串,其中每一个都保留256字节的空间,即使有些字符串的实际长度只有一两个字节。如果经常这样做,内存的浪费会很大。一种替代方法就是使用字符串指针数组,注意它的所有第二级数组并不需要长度都相同。
    如果声明一个字符串指针数组,并根据需要为这些字符串分配内存,将会大大节省系统资源。有些人把它称作“锯齿状数组”,原因是它右端的长度不一。可以通过用字符串指针填充Iliffe向量来创建一个这种类型的数组。字符串指针既可以直接现有的,也可以通过分配内存创建一个现有字符串的副本。
                            char *turnip[UMPTEEN];
                            char my_string[] = "your message here";
    /*共享字符串*/                             /*复制字符串*/ 
    turnip[i] = &my_string[0];             turnip[j] = malloc(strlen(my_string) + 1);
                                                        strcpy(turnip[j], my_string);

                                        图10-5 创建一个锯齿状数组
    只要有可能,尽量不要选择复制整个字符串的方法。如果需要从两个不同的数据结构访问它,复制一个指针比复制整个数组快得多,空间也节省很多。另一个可能影响性能的因素是Iliffe向量可能会使字符串分配于内存中的不同的页面中。这就违反了局部引用的规则(一次读写的数据位于同一个页面上),并导致更加频繁的页面交换,具体如何取决于怎样访问数据以及访问的频度。

    数组和指针参数是如何被编译器修改的
    “数组名被改写成一个指针参数”的规则并不是递归定义的。数组的数组会被改写为“数组的指针”而不是“指针的指针”。
                         实参                                                    所匹配的形参
    数组的数组                  char c[8][10];                       char (*)[10];    数组指针
    指针数组                      char *c[15];                         char **c;         指针的指针
    数组的指针(行指针)char (*c)[64];                       char (*c)[64];  不改变
    指针的指针                  char **c;                              char **c;         不改变
    之所以能在main()函数中看到char **argv这样的参数,是因为argv是个指针数组(即char *argv[])。这个表达式被编译器改写为指向数组第一个元素的指针,也就是指向指针的指针。如果argv参数事实上被声明为一个数组的数组(也就是char argv[10][15]),它将被编译器改写为char (*argv)[15](也就是一个字符数组指针),而不是char **argv。
    my_function_1(int fruit[2][3][5]) {;

    my_function_2(int fruit[][3][5]) {;
    }
    my_function_3(int (*fruit)[3][5]) {;
    }
    int apricot[2][3][5];
    my_function_1(apricot);
    my_function_2(apricot);
    my_function_3(apricot);

    int (*p)[3][5] = apricot;
    my_function_1(p);
    my_function_2(p);
    my_function_3(p);

    int (*q)[2][3][5] = &apricot;
    my_function_1(*q);
    my_function_2(*q);
    my_function_3(*q);
        图10-6 所有有效代码的组合 

    /*
    **编程挑战 
    */ 
    检验一下
    输入图10-6中的C代码,亲手运行一下。 
    #include
    #include
    my_function_1(int fruit[2][3][5]);
    my_function_2(int fruit[][3][5]); 
    my_function_3(int (*fruit)[3][5]); 
    int main( void ){
        int apricot[2][3][5];
        my_function_1(apricot);
        my_function_2(apricot);
        my_function_3(apricot);
        
        int (*p)[3][5] = apricot;
        my_function_1(p);
        my_function_2(p);
        my_function_3(p);
        
        int (*q)[2][3][5] = &apricot;
        my_function_1(*q);
        my_function_2(*q);
        my_function_3(*q);
        
        return EXIT_SUCCESS; 

    my_function_1(int fruit[2][3][5]) {
        printf( "This is the function form of my_function_1(int fruit[2][3][5])\n" );

    my_function_2(int fruit[][3][5]) {
        printf( "This is the function form of my_function_2(int fruit[][3][5])\n" );
    }
    my_function_3(int (*fruit)[3][5]) {
        printf( "This is the function form of my_function_3(int (*fruit)[2][3][5])\n" );
    }

    /* 输出:

    */ 

  • 相关阅读:
    AXI_Round_Robin_Arbiter 设计 - AW、W通道部分
    Kafka 单机部署搭建及其基本使用
    IPS: Instance Profile for Shapelet Discovery for Time Series Classification
    monaco-editor 实现SQL编辑器
    帝国EmpireCMS_7.5_SC_UTF8漏洞复现
    【无标题】
    基础算法(排序、二分、精度运算)
    网络编程之聊天室(一)
    nginx 记录每个IP连接的流量大小多少KB
    Python实操:内存管理与优化策略
  • 原文地址:https://blog.csdn.net/weixin_40186813/article/details/126091970