Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用simple函数进行静态字符数组初始化时表示长度为6,但不应为';不是一点吗?_C_Arrays_Initialization_Undefined Behavior_Strlen - Fatal编程技术网

C 使用simple函数进行静态字符数组初始化时表示长度为6,但不应为';不是一点吗?

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);

我发现这个程序继续返回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); 

    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
。关于我已经提到的答案,这只是对其他答案的补充,但我真的希望选民留下评论。但是别客气!