填充数组的机制

时间:2016-05-27 19:09:43

标签: c arrays dynamic-arrays populate

我试图填充一系列结构,定义如下:

typedef struct{
    char directive[5];
}directive_nfo_t;

使用以下内容:

directive_nfo_t directive_list[]=
{
   {"ALIGN"},{"ASCII"},{"BSS"},{"BYTE"},{"END"},{"EQU"},{"ORG"}
};

令我惊讶的是,前几个元素被破坏了:

[0]= ALIGNASCIIBSS
[1]= ASCIIBSS
[2]= BSS
...

直到我做出以下改变:

typedef struct{
    char directive[6];  <-- made char array +1
}directive_nfo_t;

然后前几个阵列是正确的:

[0]= ALIGN
[1]= ASCII
[2]= BSS
...

我的问题是在后台解释这种行为会发生什么? 问候。

5 个答案:

答案 0 :(得分:13)

在C中,字符串是一系列字符值,后跟一个0值终止符; 字符串 "ASCII"由字符序列'A''S''C''I''I'表示, 0。因此,您需要 six -element数组来存储字符串。

对于长度为N个字符的字符串,您需要一组N+1个字符来存储它。

答案 1 :(得分:3)

以您的方式将char数组显式初始化为字符串文字时:

char some_array[] = {"ALIGN"};

编译器实际上将 0th 填充到 4th “position”(共5个位置),其中包含引号内的字符,但第五个位置< / em> with \0,不要求你明确地做(如果它有足够的空间)。因此大小等于6.如果不将\0字符计入大小计算并将大小限制为5,则超出边界。编译器会省略终止字符。

在你的情况下,看起来好像下一个成员的第一个元素“覆盖”了前一个省略的 \0字符应该是什么,因为你没有预留一个它的地方。实际上,“填充数组的机制”归结为编译器编写尽可能多的数据以适应边界内部。下一个成员字符串的第一个位置的地址在逻辑上对应于您的作业,尽管前一个\0缺失。

由于您的printf() 格式标记%s,因此该函数会打印字符,直到它到达第一个\0字符,这实际上是未定义的行为。

这就是为什么

char directive[6];

在您的代码中分配了正确的大小。

答案 2 :(得分:2)

如果char数组足够大,C编译器会自动在文本后放置'\0'

如果足够大的文本,则省略该终结符,这就是这里发生的事情。

如果文本没有空间,编译器会说&#34;初始化程序太多&#34;或&#34;数组边界溢出&#34;。

struct数组元素在内存中相邻。前两个项目没有终止符,因此打印的第二个项目仅在第三个项目后的终止符处停止。第一个项目也会打印,直到达到相同的终止符。通过使数组大小为6,编译器能够在每个项目之后放置一个终结符。

答案 3 :(得分:1)

与C ++不同,C允许您(无意中)在没有空间的情况下省略NUL终止字符'\0' char终止字符char str[5] = "ALFAP"; 。为了它。您的案例可以缩小为简单的数组定义,例如:

char str[5] = {'A', 'L', 'F', 'A', 'P'};

这是一个合成的快捷方式:

"ALFAP"

这可能有点误导,因为在不同的上下文中,相同的NUL表示字符串文字,它始终具有结尾char* str = "ALFAP" // here, "ALFAP" always contains NUL character at the end 字符:

$(document).ready(function(){
 $('select option[value="0"]').attr("selected",true);

 $('.cf-table-block tbody tr').each(function () {
 $(this).find('.ddm1 option').each(function () {
  if(this.selected) {
   $('.ddm1 input').closest("tr").find(".flag input").val("g");
}
 else {
 $('.ddm2').attr('disabled', true);
    }
   }
  });
 });
});

答案 4 :(得分:1)

  

我的问题是在后台解释这种行为会发生什么?问候。

你有一个struct directive_nfo_t类型的数组,每个struct directive_nfo_t包含五个字符的数组(在你的第一个例子中)。 在directive_nfo_t类型中有5个字符数组时获得的输出基本上是由于两件事 -

  1. 数组元素存储在连续的内存位置。
  2. 在C中,字符串的抽象概念是用空终止的字符数组实现的。
  3. 当您声明了directive_nfo_t类型的数组时,directive_nfo_t的每个元素都存储在连续的内存位置,每个元素中都有5个字符数组(which are also stored in consecutive locations)。在数组的初始化列表({"ALIGN"},{"ASCII"},{"BSS"},{"BYTE"},{"END"},{"EQU"},{"ORG"})中,您已使用所有5个字符将数据存储在directive_nfo_t"ALIGN" and "ASCII")的前两个元素中。因为在C中,对字符数组进行操作以实现字符串抽象概念的函数,假设字符串将在末尾使用空字符终止。因此,在directive_nfo_t数组的前两个元素中,printf将继续打印字符,直到它到达空字符(它将在元素存储字符数组"BSS"中找到)。打印ALIGN后,printf将访问directive_nfo_tcharacter A of ASCII)数组的第二个元素的第一个字符。之所以发生这种情况是因为directive_nfo_t类型的数组的第一个元素中没有空字符,并且编译器不会像数组绑定检查那样添加超出数组大小的字符。从数组的第三个元素,您有足够的空间来表示空字符,因此printf按预期工作。

    如果分配较少的内存来存储字符数组并使用假设UNDEFINED BEHAVIOR的函数,则会得到null terminated character array。如果要在数组中存储最多MAX + 1个字符,请始终将字符数组的大小设置为MAX