简体   繁体   English

了解C中的2D数组

[英]Understanding 2d arrays in C

All i am trying with the following source code, is to understand in depth how 2d arrays (tables) works in C. The code bellow may seems much but as you can see its nothing but simple prints and assignments. 我正在尝试使用以下源代码,是为了深入了解2d数组(表)在C中的工作方式。下面的代码看起来似乎很多,但正如您看到的那样,除了简单的打印和赋值之外,什么都没有。

Code: 码:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

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

char** as = (char **)malloc(2 * sizeof(char *));
for (int i=0; i<2; i++){
    as[i] = (char *)malloc(3 * sizeof(char));
} 

strcpy(&as[0][0],"a");
strcpy(&as[0][1],"b");
strcpy(&as[0][2],"c");
strcpy(&as[1][0],"aa");
strcpy(&as[1][1],"bb");
strcpy(&as[1][2],"cc");

printf("as[0][0] <%s>\n",&as[0][0]);
printf("as[0][1] <%s>\n",&as[0][1]);
printf("as[0][2] <%s>\n",&as[0][2]);
printf("as[1][0] <%s>\n",&as[1][0]);
printf("as[1][1] <%s>\n",&as[1][1]);
printf("as[1][2] <%s>\n",&as[1][2]);

for (int i=0; i<2; i++){
    free(as[i]);
}
free(as);

/*************** PART 2 **********************/
as = (char **)malloc(2 * sizeof(int));
for (int i=0; i<2; i++){
    as[i] = (char *)malloc(3 * sizeof(int));
} 

printf("enter:as[0][0]: "); scanf("%s",&as[0][0]); // Input: a
printf("enter:as[0][1]: "); scanf("%s",&as[0][1]); // Input: b
printf("enter:as[0][2]: "); scanf("%s",&as[0][2]); // Input: c
printf("enter:as[1][0]: "); scanf("%s",&as[1][0]); // Input: aa
printf("enter:as[1][1]: "); scanf("%s",&as[1][1]); // Input: bb
printf("enter:as[1][2]: "); scanf("%s",&as[1][2]); // Input: cc

printf("as[0][0] <%s>\n",&as[0][0]);
printf("as[0][1] <%s>\n",&as[0][1]);
printf("as[0][2] <%s>\n",&as[0][2]);
printf("as[1][0] <%s>\n",&as[1][0]);
printf("as[1][1] <%s>\n",&as[1][1]);
printf("as[1][2] <%s>\n",&as[1][2]);

for (int i=0; i<2; i++){
    free(as[i]);
}
free(as);

return 0;
}

The result i am excepting is something like the tab on the left but all i am getting into ./a.out is the tab on the right 我要./a.out的结果是类似于左侧的选项卡,但我进入./a.out只是右侧的选项卡

as[0][0] <a>  }                           as[0][0] <abc>  }
as[0][1] <b>  }                           as[0][1] <bc>   }
as[0][2] <c>  }                           as[0][2] <c>    }
as[1][0] <aa> }  Excepted Result          as[1][0] <abcc> }  Final Result
as[1][1] <bb> }                           as[1][1] <bcc>  }
as[1][2] <cc> }                           as[1][2] <cc>   }

My first thought is that i am not using correctly strcpy() . 我的第一个想法是我没有正确使用strcpy() That's why / PART2 / exists in the code, but gives out the same results. 这就是代码中存在/ PART2 / /却给出相同结果的原因。

I know there is lot of same issue topics explaining 2d arrays and i did my fair research getting around the above subject. 我知道有很多相同主题的话题都在解释2d数组,而我在上述问题上做了合理的研究。 A 一种

First: you don't actually have a 2D array. 首先:您实际上没有2D阵列。

char** as = (char **)malloc(2 * sizeof(char *));
for (int i=0; i<2; i++){
    as[i] = (char *)malloc(3 * sizeof(char));
} 

This allocates a 1D array, and points as to it. 这个分配一维数组,并分as到它。 Then, for each element, it allocates space and assigns the pointer to that space to the element. 然后,为每个元素分配空间,并将指向该空间的指针分配给元素。 So what you have is a 1D array where each element is a pointer to another 1D array; 因此,您拥有的是一个1D数组,其中每个元素都是指向另一个1D数组的指针。 let's call this a "2 level array" although I'm not sure if there's a better term available. 让我们将其称为“ 2级数组”,尽管我不确定是否有更好的术语可用。

For a 2D array, you would instead write: 对于2D数组,您应该编写:

char (*as)[2][3] = malloc(2 * 3 * sizeof(char));

However, if you want the array to hold strings (as char * ) instead of individual characters then your declaration would need to be: 但是,如果要让数组保存字符串(如char * )而不是单个字符,则声明必须为:

char *(*as)[2][3] = malloc(2 * 3 * sizeof(char));

Alternatively, your original code could be changed for a 2 level array of char * : 或者,可以将原始代码更改为2级char *数组:

char*** as = malloc(2 * sizeof(char **));
for (int i=0; i<2; i++){
    as[i] = malloc(3 * sizeof(char *));
} 

In both cases, you also need to allocate storage for the strings themselves. 在这两种情况下,您还都需要为字符串本身分配存储空间。 Instead of: 代替:

strcpy(&as[0][0],"a");

you should probably use: 您可能应该使用:

 as[0][0] = strdup("a");

So, what actually happened with your code to give you the results you got? 那么,您的代码实际发生了什么,以使您获得所得到的结果? well, here: 好吧,在这里:

strcpy(&as[0][0],"a");
strcpy(&as[0][1],"b");
strcpy(&as[0][2],"c");
strcpy(&as[1][0],"aa");
strcpy(&as[1][1],"bb");
strcpy(&as[1][2],"cc");

If as is a char ** , then as[0] is a char * and as[0][0] is a simple char . 如果aschar ** ,则as[0]char *as[0][0]是简单char You are then taking the address of this and copying an entire string to it. 然后,您将获取该地址并将其复制整个字符串。 At best, this is odd; 充其量,这很奇怪。 at worst, particularly for that last line, it's undefined behaviour - because you are copying past the end of an allocated array. 在最坏的情况下,尤其是对于最后一行,这是未定义的行为-因为您正在复制已分配数组的末尾。

That is: 那是:

strcpy(&as[1][2],"cc");

You are copying to the 3rd and "4th" character of as[1] (that is, positions 2 and 3). 您将复制到as[1]的第3个和“第4个”字符(即位置2和3)。 But you only allocated space for 3: 但是您只为3分配了空间:

as[i] = (char *)malloc(3 * sizeof(char));

(In fact, an additional two lines above have the same issue, because copying a string also copies the "nul terminator" byte at the end of the string). (实际上,上面的另外两行有相同的问题,因为复制字符串还会在字符串末尾复制“ nul终止符”字节)。

When you print the strings, you print the result of the previous strcpy invocations. 在打印字符串时,将打印先前的strcpy调用的结果。 Consider, for as[0] : 考虑为as[0]

strcpy(&as[0][0],"a");

Ok, as[0] now contains "a", represented as 'a' in as[0][0] and '\\0' , the string terminator, in as[0][1] . 好的, as[0]现在包含“ a”,在as[0][0]表示为'a' ,在as[0][1]表示字符串终止符'\\0'

strcpy(&as[0][1],"b");

Now, you have 'b' in as[0][1] and '\\0' in as[0][2] . 现在,你有'b'as[0][1]'\\0'as[0][2]

strcpy(&as[0][2],"c");

As explained before, this is invalid; 如前所述,这是无效的; but supposing we ignore that for now, you end up with: 但假设我们暂时忽略了这一点,您最终会得到:

as[0][0] = 'a' as[0][1] = 'b' as[0][2] = 'c' as[0][0] ='a'as as[0][1] ='b'as as[0][2] ='c'

However, now you are printing: 但是,现在您正在打印:

printf("as[0][0] <%s>\n",&as[0][0]);

... and you say that you expect "a" as the output. ...,您说您期望输出为“ a”。 However, the string as[0] contains "abc", (and is nul terminated only due to an accident of behaviour) so that is what you get when you print it. 但是,字符串as[0]包含“ abc”(并且仅由于行为意外而以nul终止),因此在打印时将得到此结果。

To clarify: 澄清:

  • as[0] and as[1] are string pointers as[0]as[1]是字符串指针
  • as[0][i] , for any i , is a character within the string pointed to by as[0] as[0][i] ,对于任何i ,都是as[0]指向的字符串中的一个字符

When you take the address of a character within a string, and copy another string to that address, you copy over the containing string starting at that particular character. 当您获取字符串中某个字符的地址,然后将另一个字符串复制到该地址时,您将从该特定字符开始的包含字符串上进行复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM