我试图填充一系列结构,定义如下:
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
...
我的问题是在后台解释这种行为会发生什么? 问候。
答案 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个字符数组时获得的输出基本上是由于两件事 -
当您声明了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_t
(character A of ASCII
)数组的第二个元素的第一个字符。之所以发生这种情况是因为directive_nfo_t
类型的数组的第一个元素中没有空字符,并且编译器不会像数组绑定检查那样添加超出数组大小的字符。从数组的第三个元素,您有足够的空间来表示空字符,因此printf
按预期工作。
如果分配较少的内存来存储字符数组并使用假设UNDEFINED BEHAVIOR
的函数,则会得到null terminated character array
。如果要在数组中存储最多MAX + 1
个字符,请始终将字符数组的大小设置为MAX
。