C 使用simple函数进行静态字符数组初始化时表示长度为6,但不应为';不是一点吗?
我发现这个程序继续返回6,直到我开始返回16或更大,而不是1,此时程序打印0。为什么?我的意图是使用将函数的结果直接传递到静态数组初始化中C 使用simple函数进行静态字符数组初始化时表示长度为6,但不应为';不是一点吗?,c,arrays,initialization,undefined-behavior,strlen,C,Arrays,Initialization,Undefined Behavior,Strlen,我发现这个程序继续返回6,直到我开始返回16或更大,而不是1,此时程序打印0。为什么?我的意图是使用将函数的结果直接传递到静态数组初始化中 #include <stdio.h> #include <string.h> int ret_1() { return 1; } int main( int argc, const char* argv[] ) { char arr[ret_1()]; int l = strlen(arr);
#include <stdio.h>
#include <string.h>
int ret_1() { return 1; }
int main( int argc, const char* argv[] )
{
char arr[ret_1()];
int l = strlen(arr);
printf("The size is: %d\n", l);
return 0;
}
#包括
#包括
int ret_1(){return 1;}
int main(int argc,const char*argv[]
{
字符arr[ret_1()];
int l=strlen(arr);
printf(“大小为:%d\n”,l);
返回0;
}
尺寸是:6
我想知道这是一种生成任意值的未定义行为,还是我遗漏了一个潜在问题。TL;DR是的,您的代码将调用
在您的代码中,arr
是一个自动本地数组,如果未初始化,则数组的内容是不确定的
当您试图读取不确定值时,对数组应用strlen()
将调用
解决方案:如注释中所述,您可以对数组使用sizeof
运算符,该运算符处理变量的类型,而不尝试使用变量的值,从而将您从UB中解救出来
使用简单函数进行静态字符数组初始化
此声明
char arr[ret_1()];
定义由ret_1()
给定的元素组成的数组,但未对其进行初始化
那么这个电话
int l = strlen(arr);
读取(未初始化)数组的内容/元素,并以此调用未定义的行为。从现在起,任何事情都可能发生
要解决此问题,请执行以下操作:
char arr[ret_1()];
memset(arr, 0, sizeof arr); /* Initialise array by (all) zero(s). */
应用修复后,strlen(arr)
返回0
,这意味着arr
中的0
元素用于表示“字符串”。它存储与“
”等价的空字符串
注:
此表达式
sizeof arr
实际上返回为arr
分配的字节数,在您的示例中,这将是1
,除了基本问题-初始化-代码中几乎没有其他问题
strlen()
的返回类型是size\t
,因此您可能希望执行以下操作:
/* Do the initialization of the array */
size_t l = strlen(arr);
printf("The size is: %zu\n", l);
/* zu is the specifier for size_t as specified in ANSI C99 */
还请注意,可变长度数组(VLA)是一个扩展,可能无法在所有编译器中工作。例如,做
gcc -pedantic your_code.c -o your_code
应该给你
warning: ISO C90 forbids variable length array 'arr' [-Wvla ]
这里的标志-pedantic
警告使用的gnu C扩展&
-学究式错误
标志将此类诊断警告转换为错误。在您的问题printf()
等情况下,可能是一个强大的调试工具。为了调试,您可以扩展代码,添加此初始化并观察差异:
#include <stdio.h>
#include <string.h>
int ret_1() { return 1; }
int main( int argc, const char* argv[] )
{
int r = ret_1();
printf("%d\n", r);
char arr[r + 1]; //define the char array
int i = 0;
for ( ; i < r; i++ ) //initialize char the array
arr[i] = '0';
arr[r] = '\0'; //terminate it
size_t l = strlen(arr);
printf("The size is: %zu\n", l);
return 0;
}
#包括
#包括
int ret_1(){return 1;}
int main(int argc,const char*argv[]
{
int r=ret_1();
printf(“%d\n”,r);
char arr[r+1];//定义char数组
int i=0;
for(;i
那么在C语言中,“char arr[ret_1()]”也是未定义的吗?或者你是说如果我把它定义为一个单字符数组,我就不应该再有未定义的行为了?@DaveL:可能是语言问题,但是你想通过“传递…到数组中”来表达什么呢?@DaveL不,这不是造成UB的原因,问题在于使用strlen()
读取未初始化内存的内容。我明白了,谢谢你的快速回复。空终止正是我的问题。@DaveL它不仅是空终止,而且你正在读取一个单位的内存,它本身就是UB。用sizeof
替换strlen
,你的代码就会达到你所期望的效果strlen
假设数组包含一个以零结尾的字符串,但它没有。啊,这是我的问题。谢谢,我希望初始化处理空终止。@DaveL问题是arr
数组没有初始化,它包含不确定的值,因此l
最终将包含不确定的值。使用常量字符串初始化将包括终止空字符(如果适合)。但是没有初始化,所以arr
的内容完全没有定义。@如果是,大小必须是常量才能有一个初始值设定项。对于VLA,初始化必须在声明之后手动完成。可能是因为您没有回答问题。但也要注意,现代GCC使用C11而不是C90。如果您使用的是旧版本的GCC,请正确编译:GCC-std=c11-pedantic errors
,或者如果您使用的是真正的旧版本,GCC-std=c99-pedantic errors
。如果不这样做,%zu
格式说明符也将不可用。@Lundin:谢谢。每当我想在MSVC中重用代码以最小化重写时,我通常使用-std=c99--pedanticerrors
。关于我已经提到的答案,这只是对其他答案的补充,但我真的希望选民留下评论。但是别客气!