【问题标题】:ANSI C work with 2dim array throught pointersANSI C 通过指针使用 2 个 dim 数组
【发布时间】:2016-01-27 09:14:12
【问题描述】:

很久很久以前,我和C 玩了很多,但忘记了一切。现在我正在尝试解决简单的任务,但失败了。

我想编写一个接受 2dim 数组或char* 的函数并打印它。但我的代码有问题,我不明白为什么。据我了解products 是指向2dim 数组的指针,因此将其增加到i * sizeof(char**) 我得到指向子数组的指针,并增加该子数组指针我得到指向char 块的指针。但似乎我的代码正在寻找不同的内存块。

关于products数组——我知道它有N行2列。

#include <stdio.h>
#include <string.h>

void print(char*** products, size_t rows, size_t cols) {
    size_t i;

    for(i = 0; i < rows; i++) {
        printf("Col1: '%s. Col2: %s'\n",
            (products + i * sizeof(char**)),
            (products + i * sizeof(char**) + sizeof(char*))
        );
    }
}

int main(void) {
    const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
    print((char***)a, 3, 2);

    return 0;
}

【问题讨论】:

    标签: c arrays pointers multidimensional-array


    【解决方案1】:

    此声明中定义的数组

    const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
    

    类型为const char *[3][3]

    考虑到数组有三个“列”,在数组声明中明确指定了 3 列。

    const char* a[][3] =....
                   ^^^
    

    最后一列中的元素由NULL 初始化。

    当在表达式中使用数组作为参数时,它会显式转换为指向其第一个元素的指针。

    也就是说,如果您使用上面显示的数组作为参数,那么它将被转换为类型

    const char * ( * )[3]
    

    char ***不一样

    所以函数应该像这样声明

    void print( const char * ( *products )[3], size_t rows );
    

    或喜欢

    void print( const char * products[][3], size_t rows );
    

    函数应该像这样调用

    print( a, 3 );
    

    你可以再指定一个参数来设置你想要输出的列数

    void print( const char * ( *products )[3], size_t rows, size_t cols );
    

    在这种情况下,函数可以像这样调用

    print( a, 3, 2 );
    

    但是无论如何数组本身都有 3 列。:)

    或者如果编译器支持可变长度数组,例如

    void print( size_t rows, size_t cols, const char * ( *products )[cols] );
    

    为了可读性

    void print( size_t rows, size_t cols, const char * products[rows][cols] );
    

    也可以这样称呼

    print( 3, 3, a );
    

    这是一个演示程序,显示了函数声明的两种方式

    #include <stdio.h>
    #include <string.h>
    
    #define N 3
    
    void print1( const char *product[][N], size_t rows )
    {
    
        for ( size_t i = 0; i < rows; i++ ) 
        {
            for ( const char **p = product[i]; *p; ++p )
            {
                printf( "%s ", *p );
            }
            printf( "\n" );
        }
    }    
    
    void print2( size_t rows, size_t cols, const char *product[rows][cols] )
    {
    
        for ( size_t i = 0; i < rows; i++ ) 
        {
            for ( const char **p = product[i]; *p; ++p )
            {
                printf( "%s ", *p );
            }
            printf( "\n" );
        }
    }    
    
    
    int main( void )
    {
        const char * a[][N] = 
        {
            { "abc", "1" }, 
            { "def", "2" }, 
            { "ghi", "3" }
        };
    
        print1( a, N );
        printf( "\n" );
    
        size_t n = N;
    
        const char * b[n][n];
    
        memcpy( b, a, sizeof( a ) );
    
        print2( n, n, b );
        printf( "\n" );
    }    
    

    它的输出是

    abc 1 
    def 2 
    ghi 3 
    
    abc 1 
    def 2 
    ghi 3 
    

    考虑到可变长度数组(如果编译器支持它们)可能不会被初始化然后它们被定义。

    【讨论】:

      【解决方案2】:

      您混淆了您认为的列和行。解决这个问题,然后摆脱三颗星的废话,让函数接受可变数量的列,你最终会得到这个:

      #include <stdio.h>
      
      void print(size_t rows, size_t cols, const char* products[rows][cols]) 
      {
        for(size_t r=0; r<rows; r++) 
        {
          for(size_t c=0; c<cols; c++)
          {
            printf("Col%zu: %s. ", c, products[r][c]);
          }
          printf("\n");
        }
      }
      
      int main (void) 
      {
        const char* a[3][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
        print(3, 2, a);
      
        return 0;
      }
      

      就是这样,没有必要再复杂化了。

      【讨论】:

      • 在我看来,ANSI C 是在标题中指定的,我怀疑在 ANSI C 中编译。但也许 OP 被混淆了,ANSI 应该被解释为“标准”。
      • @mikedu95 使用术语“ANSI C”通常意味着您对各种标准感到困惑,see this。不再有什么叫 ANSI C,ANSI 自己叫标准INCITS/ISO/IEC 9899。为什么我应该关心美国标准协会如何称呼他们的标准对我来说并不明显,因为 ISO C 是一个国际标准。
      • 使用术语“ANSI C”意味着我的意思是“ANSI C”(ANSI X3.159-1989),这不能用 ANSI C(ANSI X3.159-1989)编译或告诉我如果我错了。就这么简单。
      • @mikedu95 我的意思是,ANSI C 这个术语被滥用得如此之多,以至于你无法知道人们是指 C90 还是仅仅指完全符合标准的 C。根据C tag wiki,除非 OP 明确说明,否则假定为最新的 C 标准。为什么要使用 27 年的标准?
      • 我同意这个术语有时被滥用的事实,这就是我留下了 OP 被混淆的可能性。但是您至少可以在答案中添加这种精确度,因为确切地说,标准已经明确指定。也许是武断的,但确实如此,所以我认为你至少应该告诉你没有考虑到它,只是使用了最新的。
      【解决方案3】:

      const char* a[][3] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};

      在这种情况下,你实际上可以这样写:

      const char* a[][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
      

      但是如果你真的想要一个 3 列的数组,你应该告诉 print 有 3 列,而不是 2。但是你的 print 当然只能打印前两列...

      然后,T 的任何 N 维数组都可以被视为T 的简单一维数组。您只需要进行一些地址计算即可访问所需的元素。一旦你有一个指向数组第一项的指针,这是可能的。所以下面是一个工作版本:

      #include <stdio.h>
      #include <string.h>
      
      typedef const char * T;
      
      void print(T *products, size_t rows, size_t cols) {
          size_t i;
      
          for (i = 0; i < rows; i++) {
              // Each row has cols items so here is the current row (i-th row):
              T *row = products + i * cols;
              printf("{%s, %s}\n", row[0], row[1]);
          }
      }
      
      int main(void) {
          T a[][3] = { { "abc", "1" }, { "def", "2" }, { "ghi", "3" } };
      
          // Tell print that there are 3 cols, not 2
          print(&a[0][0], 3, 3);
      
          return 0;
      }
      

      【讨论】:

        【解决方案4】:

        也许,这就是你想要的,更自然!

        #include <stdio.h>
        #include <string.h>
        
        void print(void *_products, size_t rows, size_t cols) {
            const char* (*products)[cols] = _products;
            size_t i;
        
            for (i = 0; i < rows; i++) {
                printf("Col1: %s. Col2: %s\n", products[i][0], products[i][1]);
            }
        }
        
        int main(void) {
            const char* a[][2] = {{"abc", "1"}, {"def", "2"}, {"ghi", "3"}};
            print(a, 3, 2);
        
            return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 2010-09-25
          • 2010-10-18
          • 2016-08-06
          • 1970-01-01
          • 2011-02-05
          • 2022-01-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多