【问题标题】:C: Initialize a constant string array dynamicallyC:动态初始化一个常量字符串数组
【发布时间】:2017-10-19 15:56:36
【问题描述】:

我知道这个问题看起来很奇怪,但我需要在 C 中初始化(或转换)一个常量字符串数组。

问题是字符串数组是动态初始化的,但我想使用的 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 限定符。

【问题讨论】:

  • 您能否说明 API 仅接受常量字符串数组的方式?是不是刚刚声明了const char,那么你也可以传递char 数组。还是测试字符串所在的内存区域?
  • 如果函数参数有const修饰符,仅表示该函数不会改变您传递的数据。 IE。您可以轻松地传递动态分配的数组。
  • @KarstenKoop API 请求的参数是 char const *const * inames, 如果我尝试传递一个字符串数组 gcc 说:expected ‘const char * const*’ but argument is of type ‘char **’
  • @EliKorvigo 但有来自 gcc 的警告 expected ‘const char * const*’ but argument is of type ‘char **’ :/
  • const char *names3[len]; ... sprintf(names3[j],"%s%d","test",j); 是错误代码。

标签: c arrays string


【解决方案1】:

从技术上讲,没有什么可以阻止您将指针转换为 (char *),然后使用 memset 或类似名称设置元素。

但是这会调用未定义的行为,因为编译器可以将其放入只读标记的内存中。

Excerpt from an answer on another SO question:

const 限定符是编译器拒绝代码的指令 试图直接修改该对象;试图修改 间接对象​​(就像您在第二个代码 sn-p 中所做的那样)导致 未定义的行为,意味着任何结果都是可能的。

没有办法(不调用 UB)在初始化后更改常量 - 所以不要这样做。

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

【讨论】:

  • int const x[2] = { rand(), rand()}; 是一个反例,“没有办法......动态初始化一个常量数组。没有 UB。你的报价是关于 assignment。(“尝试修改")。初始化是另外一回事 - 它在定义时完成并且可能是动态的。
  • @chux 对我不起作用:“test.c:7:19: error: initializer element is not constant”
  • int const x[2] = {fn(),3}; 是您的示例在全局空间中。 int const x[2] = {fn(),3}; 可以作为本地对象正常工作。
  • 旁白:C 不将1, 'a', 0xFF 称为文字常量。规范称它们为 integer-constant文字用于字符串文字复杂文字
  • @chux 谢谢!我已经相应地改变了我的答案。
【解决方案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)。
  • 好的,谢谢,它确实有效......但还有一个问题:目前我用sprintf设置内容,因为内容由字符串和整数和东西组成......但是这样做 gcc 现在有这个问题:passing argument 1 of ‘sprintf’ discards ‘const’ qualifier from pointer target type
  • @Sonnywhite 将您的数组成员分配为char *(例如char *x = malloc(size))和sprintf,然后将此指针放入您的数组中,如a[0] = x;。同样,这种转换是允许的并且是隐式的。
【解决方案3】:

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

在函数中,有多种方法可以在运行时初始化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 ** 类型调用char const *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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2011-05-07
    • 1970-01-01
    • 2021-07-02
    相关资源
    最近更新 更多