使用简单函数的静态字符数组初始化说长度是 6,但它不应该是 1 吗?
Static char array initialization with simple function says length is 6, but shouldn't it be 1?
我发现这个程序一直返回 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;
}
The size is: 6
我想知道这是否是生成任意值的未定义行为,或者是否存在我遗漏的潜在问题。
TL;DR 是的,您的代码调用了 undefined behavior.
在您的代码中,arr
是一个自动本地数组,并且未初始化,数组的内容是不确定的。
在 数组 上应用 strlen()
调用 undefined behavior,因为您正在尝试读取不确定的值。
解决方案: 正如评论中已经提到的,您可以对数组使用 sizeof
运算符,它处理 type 并且不会尝试 使用 变量的值,从而使您免于 UB。
Static char array initialization with simple function
此声明
char arr[ret_1()];
定义了一个数组,其中的元素与ret_1()
给定的元素一样多,但未初始化.
然后这个调用
int l = strlen(arr);
读取(未初始化的)数组的 content/elements 并由此调用未定义的行为。从这一刻起,任何事情都可能发生。
要解决此问题,请执行以下操作:
char arr[ret_1()];
memset(arr, 0, sizeof arr); /* Initialise array by (all) zero(s). */
应用修复后,strlen(arr)
returns 0
,意味着 arr
中的 0
个元素用于表示 "string" .它存储相当于 ""
的空字符串。
注:
此表达式 sizeof arr
实际上 returns 分配给 arr
的字节数,在您的示例中为 1
.
除了基本问题 - 初始化 - 您的代码几乎没有其他问题。
strlen()
的 return 类型是 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 扩展 &
-pedantic-errors
标志将此类诊断警告转换为错误。
在像您的问题这样的情况下,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] = '[=10=]'; //terminate it
size_t l = strlen(arr);
printf("The size is: %zu\n", l);
return 0;
}
我发现这个程序一直返回 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;
}
The size is: 6
我想知道这是否是生成任意值的未定义行为,或者是否存在我遗漏的潜在问题。
TL;DR 是的,您的代码调用了 undefined behavior.
在您的代码中,arr
是一个自动本地数组,并且未初始化,数组的内容是不确定的。
在 数组 上应用 strlen()
调用 undefined behavior,因为您正在尝试读取不确定的值。
解决方案: 正如评论中已经提到的,您可以对数组使用 sizeof
运算符,它处理 type 并且不会尝试 使用 变量的值,从而使您免于 UB。
Static char array initialization with simple function
此声明
char arr[ret_1()];
定义了一个数组,其中的元素与ret_1()
给定的元素一样多,但未初始化.
然后这个调用
int l = strlen(arr);
读取(未初始化的)数组的 content/elements 并由此调用未定义的行为。从这一刻起,任何事情都可能发生。
要解决此问题,请执行以下操作:
char arr[ret_1()];
memset(arr, 0, sizeof arr); /* Initialise array by (all) zero(s). */
应用修复后,strlen(arr)
returns 0
,意味着 arr
中的 0
个元素用于表示 "string" .它存储相当于 ""
的空字符串。
注:
此表达式 sizeof arr
实际上 returns 分配给 arr
的字节数,在您的示例中为 1
.
除了基本问题 - 初始化 - 您的代码几乎没有其他问题。
strlen()
的 return 类型是 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 扩展 &
-pedantic-errors
标志将此类诊断警告转换为错误。
在像您的问题这样的情况下,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] = '[=10=]'; //terminate it
size_t l = strlen(arr);
printf("The size is: %zu\n", l);
return 0;
}