清空字符数组 c

117

我以为将第一个元素设置为null会清空char数组的所有内容。

char my_custom_data[40] = "Hello!";
my_custom_data[0] = '\0';

然而,这只将第一个元素设置为null。

或者

my_custom_data[0] = 0; 

我认为,与其使用 memset,上面两个示例清除所有数据的做法更好。


1
Jared,你为什么设置C++标签?他讲的是“C”,并没有添加任何与C++相关的标签。 - Johannes Schaub - litb
2
这同样适用于C++中的字符数组,即使他没有明确指定。 - Adam Hawes
4
为避免出现人们提供特定于C++的解决方案的情况,我已删除了C++标签。 - Alnitak
16个回答

128

这取决于你想如何查看数组。如果你将数组视为一系列字符,则清除数据的唯一方法是触碰每个条目。memset可能是实现此目的最有效的方式。

另一方面,如果您选择将其视为C/C++空终止字符串,将第一个字节设置为0将有效地清除该字符串。


4
答案中的关键词是“有效地”。只有第一个元素被设置为0,其余元素仍具有未定义的值,但如果您将数组视为以空字符结尾的字符串,并且第一个元素为空,则该字符串被认为是空的。 - Arnold Spence
关于“最有效”的问题 - 请参见https://dev59.com/83RB5IYBdhLWcg3w9b19#455137 - Johann Gerell
你应该知道,在ANSI C(至少)中,数组[] = {0};只有在你定义一个数组时才能使用,如果你后来尝试这样做,将会得到编译错误! - hhafez
谢谢你的回答,现在我更明白了。但是如果使用fprintf打印字符数组,它会打印到空指针为止吗?还是会打印数组中剩下的垃圾数据? - SSH This
哦,这真的很老了...好吧在这里,“清除字符串”需要更多的定义。查看字符串的c函数假定如果它们找到一个'\0'字符(空值),那么这就是字符串的结尾。这就是“空终止字符串”的定义。哦,这真的很老了...好吧因此,如果您将char数组的第一个字符设置为null字符,则具有零字符(空)空终止字符串。数组中的其他内容都不相关。 - Mister Jeps
显示剩余4条评论

82
在C中,数组只是一个内存位置,因此你的my_custom_data[0] = '\0';赋值只是将第一个元素设置为零,其余元素保持不变。如果你想清空数组的所有元素,则需要访问每个元素。这就是memset的作用:
memset(&arr[0], 0, sizeof(arr));

这通常是处理此问题的最快方法。如果您可以使用C ++,请考虑使用std :: fill:

char *begin = &arr;
char *end = begin + sizeof(arr);
std::fill(begin, end, 0);

2
我认为第二个版本应该是: std::fill( arr, arr+ sizeof(arr)/sizeof(arr[0]), 0 ); - David Rodríguez - dribeas
澄清:不要在使用fill时使用sizeof,因为之后在int、long、double等数组中会遇到问题。 - Zan Lynx
1
我更喜欢使用:std::fill(&arr[0], &arr[arr_len], 0); - Zan Lynx
专业提示:使用以下宏可以获取准确的数组大小,无论类型是什么 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) - Someone Somewhere
为什么不直接使用memset(arr, 0, sizeof(arr));呢? - ratojakuf
显示剩余5条评论

27
为什么你认为设置一个单独的元素会清空整个数组呢? 在C语言中,除非程序员明确编写代码,否则很少发生任何事情。 如果将第一个元素设置为零(或任何值),那么你就已经做到了这一点,没有更多的操作。
在初始化时,你可以将数组设置为零:
char mcd[40] = {0}; /* sets the whole array */

否则,我不知道除了memset或类似的技术以外还有什么别的方法。


我想这取决于您使用的编译器。 - cocoafan
1
@cocoafan:不,这不是编译器相关的。这是语言规范的一部分。任何行为不同的编译器都没有遵循C语言。 - abelenky
我不知道这个,谢谢。我找不到任何资源可以阅读这个特殊情况。如果能够将其作为书签就太好了。 - cocoafan
1
它被称为部分初始化。我没有C99规范,但这里有两个来源:http://bit.ly/enBC2m “您不需要初始化数组中的所有元素。如果数组部分初始化,则未初始化的元素将接收适当类型的值0。”http://bit.ly/f9asHH “如果初始化程序少于数组中的元素,则剩余的元素会自动初始化为0” - abelenky
这不适用于已经声明并分配值的数组,对吧? - skinnedknuckles

12

使用:

memset(my_custom_data, 0, sizeof(my_custom_data));

或者:

memset(my_custom_data, 0, strlen(my_custom_data));

2
第二个选项(memset(my_custom_data, 0, strlen(my_custom_data));)只会清除到第一个'\0',这可能超出数组的末尾。这可能是可以接受的,也可能不可以。 - brewmanz
第一个选项在我尝试了很多其他方法之后,在ESP32上运行良好。 - theGtknerd

10

试试以下代码:

void clean(char *var) {
    int i = 0;
    while(var[i] != '\0') {
        var[i] = '\0';
        i++;
    }
}

2
请注意 - 请使用4个空格缩进代码或选择代码并点击“代码”按钮,该按钮看起来像两行二进制代码。 - user229044
如果您不想包含string.h来使用memset(),这是一个非常好的解决方案。 - Akash Agarwal

7

为什么不使用memset()?这就是做法。

设置第一个元素会保留其余内存不变,但是str函数将把数据视为空。


1
不要为了可读性而使用memset:https://dev59.com/questions/83RB5IYBdhLWcg3w9b19#455137 - Johann Gerell
2
那么你的答案是什么? - mkb

6

请看以下内容,我已经用数组中的数据解释了情况1和情况2。

char sc_ArrData[ 100 ];
strcpy(sc_ArrData,"Hai" );

案例1:

sc_ArrData[0] = '\0';

结果:

-   "sc_ArrData"
[0] 0 ''
[1] 97 'a'
[2] 105 'i'
[3] 0 ''

案例二:

memset(&sc_ArrData[0], 0, sizeof(sc_ArrData));

结果:

-   "sc_ArrData"
[0] 0 ''
[1] 0 ''
[2] 0 ''
[3] 0 ''

虽然将第一个参数设置为 NULL 可以解决问题,但建议使用 memset。

5
我通常这样做:

我通常就像这样做:

memset(bufferar, '\0', sizeof(bufferar));

4

不对。你所做的只是将第一个值设置为 '\0' 或 0。

如果你正在使用以 null 结尾的字符串,则在第一个示例中,你将获得模拟预期行为的结果,但是内存仍然被设置了。

如果想要清除内存而不使用 memset,请使用循环语句。


我不赞成使用for循环。尽量不要编写自己的“改进”(通常并非如此)库函数。实际上,memset和memcpy都是相当特殊的函数,并且根据所知道的数据对齐和长度,通常会被内联为CPU定制的机器代码。 - Zan Lynx
@Zan,原帖作者不想使用memset(也许他是嵌入式的,没有可用的memset)。但是,memset通常是高度优化的,很可能比for循环更快。 - Adam Hawes
真的,然而他不想使用memset,所以我建议用for循环。 - Alan

2
您应该使用memset。仅设置第一个元素是不起作用的,您需要设置所有元素-如果不这样做,那么您如何将仅第一个元素设置为0?

memset不应该用于牺牲可读性:https://dev59.com/83RB5IYBdhLWcg3w9b19#455137 - Johann Gerell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接