在C语言中动态初始化一个常量字符串数组

3

我知道这个问题似乎很奇怪,但我需要在C语言中初始化(或转换)一个常量字符串数组,内容涉及IT技术。

问题在于,字符串数组是动态初始化的,但我想使用的API函数只接受常量字符串数组。

我知道这样可以解决问题:

const char *const arr[] = { "test" };

但是:由于我不知道数组会有多少项,也不知道内容预运行时是什么,所以我不能用那种方式初始化数组。

因此,这当然行不通。

const char *const arr[1]; 
arr[1] = "test"; // won't work

我的问题是:是否有可能将动态字符串数组转换为只读的?或者有没有一种方法可以动态地初始化数组?
编辑1:我的确切问题是什么?
int len = 8;
const char *names1[8] = {"test0","test1","test2","test3","test4","test5","test6","test7" }; // not what I'm looking for
const char *names2[len]; 
const char *names3[len];

// nearly what I'm looking for
for(int j=0; j<len; j++) {
    names2[j] = "test";
}

// exactly what I'm looking for
for(int j=0; j<len; j++) {
    sprintf(names3[j],"%s%d","test",j); // discards 'const' qualifier
}

// ...

Cudd_DumpDot(gbm, 1, ddnodearray, names1, NULL, outfile);
Cudd_DumpDot(gbm, 1, ddnodearray, names2, NULL, outfile);
Cudd_DumpDot(gbm, 1, ddnodearray, names3, NULL, outfile); // won't work

好的,这是我目前的进展。 使用names2方法确实有效,但我想使用sprintf(如names3中所示),因为在这种情况下我需要附加j。但这将伤害const限定符。


1
您能澄清API仅接受常量字符串数组的方式吗?它只是声明为 const char,然后也可以传递 char 数组。还是它会测试字符串所在的内存区域? - Karsten Koop
1
如果一个函数参数有const修饰符,那么它只意味着该函数不会改变您传递的数据。也就是说,您可以轻松地将动态分配的数组按原样传递。 - Eli Korvigo
@Sonnywhite 该评论与发布的代码不符。评论参数指向char *,而代码中的arr元素是const char *。因此,您在评论中的目标与问题说明不同。最好发布您真正失败的代码。 - chux - Reinstate Monica
1
const char *names3[len]; ... sprintf(names3[j],"%s%d","test",j); 是糟糕的代码。 - chux - Reinstate Monica
显示剩余7条评论
3个回答

3
从技术上讲,你可以将指针强制转换为 (char *),然后使用 memset 或类似函数设置元素。但是这会导致未定义的行为,因为编译器可能会将其放入只读标记内存中。 另一个 SO 问题的答案摘录如下:

const 限定符是一条指令,告诉编译器拒绝直接修改该对象的代码;试图间接修改对象(正如你在第二个代码片段中所做的那样)会导致未定义的行为,这意味着任何结果都有可能。

没有办法(不触发未定义的行为)在初始化后更改常量 - 所以不要这样做。

更新 正如 @chux 在评论中指出的那样,确实可以 动态地 初始化局部变量。


“int const x[2] = { rand(), rand()};”是一个反例,证明了“无法动态初始化常量数组”的说法不正确。它没有UB(undefined behavior)。你引用的内容是关于“赋值”的。而“初始化”是不同的,它在定义时完成且可以是动态的。 - chux - Reinstate Monica
@chux 对我不起作用:"test.c:7:19: 错误:初始化元素不是常量" - Marco
1
int const x[2] = {fn(),3}; 这个例子在全局空间中。int const x[2] = {fn(),3}; 作为一个局部对象也可以正常工作。 - chux - Reinstate Monica
1
附注:C语言不将1,'a',0xFF称为字面常量。规范将它们称为“整数常量”。而“字面值”一词则用于表示“字符串字面值”和“复合字面值”。 - chux - Reinstate Monica
1
@chux 谢谢!我已经相应地修改了我的回答。 - Marco
显示剩余2条评论

2

我想要使用的API函数只接受常量字符串数组。

这不是传递指向常量指针数组的理由...将转换为const(在此情况下是常量数组元素)是允许的(甚至是隐式的),因此下面这段(荒谬的)代码可以编译得很好:

const char *test(const char *const *foo)
{
    return foo[0];
}

int main(void)
{
    const char *arr[10];
    arr[0] = "Foobar";

    const char *x = test(arr);
    return (int) *x;
}

只有当arr是指向*const*的指针数组时,它才能完美地工作。如果您使用char* arr[10];声明它,则会收到来自gcc的警告(-Wincompatible-pointer-types)。 - cmaster - reinstate monica
好的,谢谢。它确实起作用了...但是还有一个问题:目前我使用sprintf设置内容,因为内容包含字符串、整数等等...但是这样做会导致gcc出现问题:passing argument 1 of ‘sprintf’ discards ‘const’ qualifier from pointer target type - Sonnywhite
@SonnyWhite 请将您的数组成员分配为“char *”(例如使用“char *x = malloc(size)”),然后在其中进行sprintf操作,然后将此指针放入您的数组中,如“a [0] = x;”。再次强调,此转换是被允许且隐式的。 - user2371524

1

动态初始化常量字符串数组

在函数内部,有多种方法可以在运行时初始化 const 字符串数组。

// example
const char *s[2] = { (char [3]){ rand(), 0, 0},(char [3]){ rand(), 0, 0} }; 

然而,看起来 OP 只需要类似这样的东西。

从各种字符串中,每个都在有效的内存中。

// Exmaple
#define SZ (4 + 11 + 1)
char buf[len][SZ];
for(int j=0; j<len; j++) {
  sprintf(buf[j],"%s%d","test",j);
}

形成一个const char *的数组

  const char *names[len];
  for(int j=0; j<len; j++) {
    names[len] = buf[len];
  }

调用 Cudd_DumpBlifBody()。参数 char const *const * 可以使用类型 char const *const *char const ** 进行调用。

#include <stdio.h>
#include <stdlib.h>

typedef void DdManager;
typedef void DdNode;
int Cudd_DumpBlifBody(DdManager *dd, int n, DdNode **f, 
    char const *const *inames, 
    char const *const *onames, FILE *fp, int mv) {
  return 0;
}
#define SZ (4 + 11 + 1)

int sw(int len) {
  char buf[len][SZ];
  const char *names[len];
  for(int j=0; j<len; j++) {
    sprintf(buf[j],"%s%d","test",j);
    names[len] = buf[len];
  }
  char const *const *inames = names;
  char const *const *onames = names;
  return Cudd_DumpBlifBody (NULL, 0, NULL, inames, onames, NULL, 0);
}

本地对象,例如char buf[len][SZ];,可能会因为本地存储空间不足而变得过大。如果不确定或者len可能很大,请考虑使用*alloc()

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