【问题标题】:How to initialize only a slice of a character array?如何仅初始化字符数组的一部分?
【发布时间】:2018-01-02 10:06:42
【问题描述】:

我知道 C 的(非常简洁的)数组初始化语法,比如

char arr[12] = {[0] = '\n', [4] = 'z'};

初始化数组中的一些特定成员,但是有没有办法用字符串初始化整个数组块?像这样:

char filename[12] = {[0..9] = "data/img/"};

是否有允许它的内置语法?还是我必须坚持 memcpy():

char filename[strlen(basename) + 14];
memcpy(filename, "data/img/", 9);
memcpy(filename + 9, basename, l);
memcpy(filename + 9 + l, ".bmp", 4);
filename[l + 13] = '\0';

是我目前拥有的; filename 是涉案字符数组,basename 是可变字符串。

【问题讨论】:

  • 我认为如果您询问例如问题可能会变得更清楚。 [3..9],来自[0] 的切片不太有趣。或者它们是你真正要问的?
  • 是的,我想要一个以常量字符开头的字符串,然后附加其他(变量)字符
  • 然后edit你的问题是模棱两可的,有人已经部分回答了。
  • 顺便说一句,我正在使用 VLA。这可能会使事情复杂化(Antti Haapala 的解决方案不起作用)
  • "我正在使用 VLA" 你真的应该在你的问题中提到这一点。特别是因为您给出的第一个示例不适用于 VLA!

标签: c initialization slice array-initialization


【解决方案1】:

如果你想使用可变长度数组,初始化是不可能的,但为什么不使用 snprintf 而不是使用手动计算偏移量的 memcpy 链呢?

snprintf(filename, sizeof(filename), "data/img/%s.bmp", basename);

如果您不想手动计算 VLA 的尺寸,可以调用 snprintf 并使用 null 目标,让它为您计算结果字符串长度:

int len = snprintf(NULL, 0, "data/img/%s.bmp", basename);
char filename[len + 1];

(但请确保两次调用使用相同的格式字符串和参数。)

【讨论】:

  • 另外,如果字符串大部分都很小,可以在第一个snprintf中对堆栈分配的缓冲区使用很好的猜测,如果这还不够,那么malloc必要的大小并做@987654328 @ 再次。在大多数情况下,这将避免双重调用。
  • 注意:不幸的是 snprintf() 返回一个有符号整数值。
  • @joop:哦,是的。如果返回一个负值表示错误,那将破坏堆栈。解决了这个问题。
  • 如果返回负值,“固定”码仍然是UB;从技术上讲,您应该检查一下
  • 第一次调用,sprintf 不够吗?
【解决方案2】:

(请注意所有投票者,此答案是在添加有关 VLA 信息的编辑前 18 分钟写的)

怎么了

char arr[12] = "string";

这将使用"string"的字符初始化元素0 .. 5,使用终止NUL的元素6并设置其余部分将其余部分也设置为 NUL。

GCC 有一个扩展,您可以在其中使用 single 值初始化数组的范围,即

char arr[12] = {[1 ... 7] = 'a'};

但它不适用于字符串。


初始化程序根本不适用于可变长度数组。在这种情况下使用sprintf

【讨论】:

  • 也许他更喜欢:char arr[12] = {[1..7] = "string"};?或者类似的。没有DV,顺便说一句。
  • @joH1 也感谢你把问题变成了变色龙
【解决方案3】:

虽然这可行:

const char * basename = "base";

char filename[strlen(basename) + 14];
memcpy(filename, "data/img/", 9);
memcpy(filename + 9, basename, l);
memcpy(filename + 9 + l, ".bmp", 4);
filename[l + 13] = '\0';

这很复杂且容易出错。

对于“字符串”('\0'-terminated char-arrays),有 str*() 系列函数。

像这样使用它:

char filename[strlen(basename) + 14]; 
strcpy(filename, "data/img/"); /* Sets filename including the final 0. */
strcat(filename, basename); /* Appends to filename including the final 0.  */
strcat(filename, ".bmp"); /* ditto */

【讨论】:

  • @joH1:请注意,第一个电话不是strcat(),而是strcpy()
  • 是的,我已经看到了。不过,这可能是一个微妙但令人毛骨悚然的错误
  • snprintfsprintf ,国际海事组织,比其中任何一个都不容易出错
  • @M.M:如果运行两次,是的。
  • 你的解决方案是 O(n²) 不是 C 的真正目的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-03
  • 2011-12-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多