1

我在处理多维数组时遇到了问题。我试图让“123”“456”“X123”和“x456”在屏幕上出现使用指针的函数里面:在C中迭代多维数组而不知道索引

void f(char ***array){ 
    while (**array != '\0'){ 
     while (*array != '\0'){ 
      printf("%s\n",*array);array++; 
     } 
    } 
} 

int main(){ 
    char* arr[50][50]={{"123","456"},{"X123","X456"}}; 
    f(arr); 
    return 0; 
} 

编译时,我收到了警告passing argument 1 of 'f' from incompatible pointer type在该行f(arr);。并在运行代码时,我看到:

123 
456 
Segmentation fault 

程序退出。

当我将代码改成这样:

void f(char **array){ 
    while (*array != '\0'){ 
     printf("%s\n",*array);array++; 
    } 
} 

int main(){ 
    char* arr[50]={"123","456"}; 
    f(arr); 
    return 0; 
} 

的数字重复罚款,但我宁愿我的组数据成组在某些时候更好的组织。为什么第一组具有多维数组的代码不能正确执行?

+2

三颗星?重新思考代码的时间,但无法找到相关链接,除非http://stackoverflow.com/questions/10087113/how-many-levels-of-pointers-can-we-have –

+0

C多维数组* * *与指向数组的指针数组一样。你需要写'void f(const char * array [] [50]){...}'。或者,使用GNU非编译时常量多维数组维度:void f(const int cols,const char * array [] [cols]){...}。自从我这样做以来已经有一段时间了,但我认为这是有效的。无论是或者你的函数内部,你都必须将'array'转换为指向该类型数组的指针。 –

+1

@PeterCordes作为参数的尺寸是C99的一部分。 – Jason

回答

0

很难说出你正在尝试做什么,但是如果我理解正确,你似乎有一个不需要的额外数组维度。您到达第5个字符串后即刻测试未初始化的值(导致您的段错误)。要纠正它,你可以这样做:

#include <stdio.h> 

void f(char **array){ 
    while (*array != '\0'){ 
     // while (*array != '\0'){ 
     printf("%s\n",*array);array++; 
     //} 
    } 
} 

int main(){ 
    char *arr[50]={"123","456","X123","X456",NULL}; 
    f(arr); 
    return 0; 
} 

输出

$ ./bin/func_f 
123 
456 
X123 
X456 

注:明确NULL用作定点停止迭代时,数据被用尽。有很多方法可以解决这个问题,这只是一个。

2

首先,为什么三颗星?你试图完成什么? 显而易见的解决方案是创建一个二维字符数组,然后将该字符串存储在数组中,每行一个。请看下面的例子:

char arr[][ 6 ] = { "123", "456", "X123", "X456" }; 

注意,我们被允许省略arr阵列中的行数,但C要求我们指定的列数。不幸的是,并非所有的字符串都足够长以填充整行数组,所以C用空字符填充它们。 (请注意,有一点浪费的空间阵列中)

 0  1  2  3  4  5 
    +-----+-----+-----+-----+-----+-----+ 
0 | 1 | 2 | 3 | '\0'| '\0'| '\0'| 
    +-----+-----+-----+-----+-----+-----+ 
1 | 4 | 5 | 6 | '\0'| '\0'| '\0'| 
    +-----+-----+-----+-----+-----+-----+ 
2 | X | 1 | 2 | 3 | '\0'| '\0'| 
    +-----+-----+-----+-----+-----+-----+ 
3 | X | 4 | 5 | 6 | '\0'| '\0'| 
    +-----+-----+-----+-----+-----+-----+ 

如果在你的代码有三颗星是你想要的东西,那么你将不得不增加一个额外的元素,它始终为NULL。 (顺便说一句,为什么你不想使用数组的长度?)

另一种方法是使用一个衣衫褴褛的数组。 C没有提供“粗糙的数组类型”,但它确实为我们提供了模拟其中的工具。 (只是创建一个数组,其元素是指向字符串),请看下面的例子:

#define N 4 

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

    char *str[] = { "123", "456", "X123", "X456" }; 

    for (char **p = &str[ 0 ]; p < str + N; ++p) { 
     puts(*p); 
    } 

    return EXIT_SUCCESS; 
} 

要访问字符串中的一个,我们需要的是下标arr阵列。

希望这会有所帮助..

0

您通常不应该互换使用指针和数组。常识是他们是一样的,但他们不是。对于多维数组尤其如此。

多维数组必须在内存中线性布局,因为地址是线性的。有几种方法可以做到这一点,但C使用行主排序。这意味着最后一个指数随着地址的增加而增长最快。

例如,二维阵列

int x[rows][cols]; 

两个语句将相当于

x[row][col] = y; 
*(x + (row * cols) + col) = y; 

这意味着,为了访问自己的多维阵列的元件在一个功能,该功能需要至少知道可以有效访问的较高维度的大小。

void f(int rows, int cols, char* array[rows][cols]){ 
    for (int i = 0; i < rows; i++) { 
    for (int j = 0; j < cols; j++) { 
     printf("%s\n", array[i][j]); 
    } 
    } 
} 

int main(){ 
    char* arr[50][50]={{"123","456"},{"X123","X456"}}; 
    f(50, 50, arr); 
    return 0; 
} 

但是,如果有必要不知道尺寸迭代,你可以把内存布局的优势,有效地迭代的行和列(领域,更高层次)。尽管如此,这增加了阵列中输入信号的必要性(例如NULL)。除了使代码更复杂外,它还会增加内存开销,因为通常必须分配最后一行包含NULL

#include <stdio.h> 

void f(char** array){ 

    while (*array) 
    printf("%s\n", *(array++)); 
} 

int main(){ 

    char* arr[][2] = { {"123","456"}, {"X123","X456"}, {NULL, NULL} }; 

    f((char**) arr); 

    return 0; 
} 
+0

你最后的代码是一个想法,但我仍然''在编译时从'不兼容的指针类型''传递'f'的参数1,并且在执行时传递段错误。也许我的问题没有真正的答案,因为每个人都建议我只使用单一维度。 – Mike

+0

@Mike我写的最后一个版本太快了,看到上面的变化。这是交换使用指针和数组不好的原因之一。 – Jason