Sonnywhite
Sonnywhite

Reputation: 136

C: Initialize a constant string array dynamically

I know the problem seems weird but I need to initialize (or convert) a constant string array in C.

The problem is that the string array is initialized dynamically but an API function I'd like to use only accepts constant string arrays.

I know that this works:

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

But again: Since I don't know how many items the array will have nor I know the content pre runtime, I can't initialize the array that way.

So of course this won't work

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

My question is: Is it possible to convert somehow the dynamically string array to a read-only one? Or is there a way to initialize the array dynamically once?

EDIT 1: My exact problem

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

Okay this is my progress so far. The method with names2 is indeed working but I'd like to use sprintf (as shown with names3) since I need to append j in this case. And this would wound the const qualifier.

Upvotes: 3

Views: 2095

Answers (3)

Marco
Marco

Reputation: 7287

Technically there is nothing stopping you from casting the pointer to (char *) and then setting the elements with memset or alike.

However this invokes undefined behaviour since the compiler can put it into read-only marked memory.

Excerpt from an answer on another SO question:

The const qualifier is an instruction to the compiler to reject code that attempts to modify that object directly; attempts to modify the object indirectly (as you do in the second code snippet) results in undefined behavior, meaning any result is possible.

There is no way (without invoking UB) to change a constant after its initialisation - so don't do that.

UPDATE As @chux pointed out in the comments it is indeed possible to dynamically initialize local variables.

Upvotes: 3

chux
chux

Reputation: 154055

Initialize a constant string array dynamically

Within a function, there are various ways to initialize a const string array at run-time.

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

Yet it appears OP needs only something like that.

Form the various strings, each in valid memory.

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

Form an array of const char *

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

Call Cudd_DumpBlifBody(). The char const *const * parameters can be called with type char const *const * or 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);
}

Local objects like char buf[len][SZ]; could easlily get too large for local storage. Consider *alloc() if unsure or if len could be large.

Upvotes: 1

user2371524
user2371524

Reputation:

an API function I'd like to use only accepts constant string arrays.

That's no reason to pass an array of constant pointers ... the conversion to const (in this case constant array elements) is allowed (and even implicit), so the following (nonsensical) code compiles just fine:

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;
}

Upvotes: 2

Related Questions