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.
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.
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;
}
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.
Related
I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);
The following is a snippet of code that parses tokens and stores them. The code compiles and works.
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int storeTokens(char *src, char *delim, char **storage, size_t len) {
int idx = 0;
char str[100] = {0};
char *token = NULL;
char *saveptr = NULL;
// copy string so we don't modify the source
if (snprintf(str, sizeof(str), "%s", src) < 0) {
return 0;
}
// Loop through string and parse out tokens
token = strtok_r(str, delim, &saveptr);
while ((token != NULL) && (idx < len)) {
snprintf(storage[idx], sizeof(storage[idx]), "%s", token);
strcpy(storage[idx++], token);
token = strtok_r(NULL, delim, &saveptr);
}
// Print the tokens
int i = 0;
for (i = 0; i < idx; i++) {
printf("fun: %s\n", storage[i]);
}
return idx; // number of tokens found
}
int main() {
int i = 0;
char teststr[] = "This*is*my*string*.";
char *storageptr[72];
char storage[72][255];
// Assign storage space to the pointers
for (i = 0; i < 72; i++) {
storageptr[i] = storage[i];
}
// Parse the tokens
int numtokens = storeTokens(teststr, "*", storageptr, 72);
// Print the tokens
for (i = 0; i < numtokens; i++) {
printf("storage: %s\n", storage[i]);
}
return EXIT_SUCCESS;
}
Output
fun: This
fun: is
fun: my
fun: string
fun: .
storage: This
storage: is
storage: my
storage: string
storage: .
The function stores the string with the char **storage variable. The reason for this being a double pointer is so the function can be used on any storage regardless of the length.
My problem is passing the storage into the function. As you can see in main, I created storageptr to point to storage before passing it to the function.
This seems convoluted and unnecessary. Not to mention the time wasted looping and linking each string. However I can't figure out how to pass storage directly into the function without creating storageptr.
I've done reading such as Passing an array of strings to a C function by reference, but nothing really clicks. I can't seem to figure out how to properly pass storage into the function.
Using a C99 or C11, having optional VLA support, compatible compiler you can pass directly the 2D array specifying dynamically the size of your array:
int storeTokens(char *src, char *delim, size_t len, size_t size, char storage[len][size]);
Call from main:
int numtokens = storeTokens(teststr, "*", 72, 255, storage);
If you have a C11 compiler to be sure that it supports VLA's (that are optional for C11) check the symbol STDC_NO_VLA, if it is defined the compiler does not support VLA's.
Unless you need to keep the argument as a pointer to pointer (to char), then to be able to pass the array of arrays (of char) directly you need to change the function signature:
int storeTokens(char *src, char *delim, char (*storage)[255], size_t len)
// ^^^^^^^^^^^^^^^
Now you can pass storage from the main function:
storeTokens(teststr, "*", storage, 72)
The problem is that while arrays can decay to a pointer to its first element, it's not "recursive".
If you have an array like yours
char storage[72][255];
then when it decays to a pointer to its first element it is &storage[0], which is a pointer to an array. This secondary array will not decay, so passing storage will pass a pointer to an array (of type char (*)[255]).
If you must pass a char **, then the intermediate storageptr array is needed.
I want to implement my own string implementation for education. For that I defined a struct named string as follows:
struct string {
const char *const data;
const int length;
};
I use functions to create these string structs and then I assign them to variables.
In order to override the const int length I use the following trick:
*(int *) &result.length = // a int
Now I also want to write to the const char *const data.
As far as I know the first const makes sure that you cant edit the items at which the pointer points, and the second const is that you can't point the pointer to a different memory location. These are properties of an immutable string. So my question is: How can I assign something to the const char *const data like I did to the const int length?
Edit: result as shown above is an instance of the struct string
Form the struct string at its declaration and initialize it.
Also recommend to store the size and not the length and use size_t.
#include <stdio.h>
#include <stdlib.h>
struct string {
const char * const data;
const size_t size;
};
struct string string_copy(const char *src) {
size_t size = strlen(src) + 1;
char *copy = malloc(size);
if (copy) {
memcpy(copy, src, size);
} else {
size = 0;
}
struct string retval = {copy, size}; // ****
return retval;
// or return a compound literal (C99)
return (struct string){ copy, size};
}
void string_free(struct string s) {
free((void*)s.data);
}
int main(void) {
struct string a = string_copy("Hello");
printf("%zu <%s>\n", a.size, a.data);
string_free(a);
// do not use `a` subsequently
return 0;
}
I do not recommend to initialize with a string literal like struct string retval = {"World", 6}; as that limits the usefulness of struct string.
Using a opaque struct has many advantages #Jonathan Leffler that exceed this approach - mainly to keep other code from messing with the struct string.
I have a main file, and a header file.
In main file, I want to return a 2D char array from a char function from header file. My char function is as following:
char character_distribution(int length, char redistribution[length][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
return redistribution;
}
And my main function is as follows:
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length;
char distribution[length][2];
distribution = character_distribution(length, distribution[length][2]);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
When I run my code, I get the following error:
warning: return makes integer from pointer without a cast
How can I fix the problem?
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
int main()
{
int length = 2; //initialize
char distribution[length][2];
character_distribution(length, distribution);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
return 0;
}
If you really have to return the 2d array, one way (easy way) is to just put it in a struct
struct distribution_struct {
char x[256];
char y[2];
};
struct distribution_struct character_distribution(int length, char redistribution[][2]) {
struct distribution_struct dis;
//initialize the struct with values
//return the struct
}
And another way is to manually allocate memory for the 2d array in the function and return it
char** character_distribution(int length, char redistribution[][2]) {
//use malloc to create the array and a for loop to populate it
}
You cannot actually return an array from a C function. You can, however, return a pointer to such an array. The correct declaration in that case is:
char (*character_distribution(int length, char redistribution[][2]))[][2]
Sizing the initial dimension is not necessary and not, I suspect, actually conformant with standard C (at least, sizing it with length as you did in your question looks dubious to me). This is because arrays are passed by reference implicitly (and in this case, returned by reference explicitly) and it is not necessary to know the first dimension in order to calculate the address of an element having been given a pointer to the array (and the indices).
Note that you should not return a pointer to an array that is scoped locally to the function, since its storage is deallocated once the function returns (and such a pointer would then be invalid).
However, your question shows that you don't really need to return an array. Since arrays are passed by reference anyway, altering the passed-in array will causes changes that are also visible to the caller. Your code could be written as:
void character_distribution(int length, char redistribution[][2])
{
char *buffer, distribution[256][2] = {0};
long lSize;
struct Bar result = funct();
buffer = result.x;
lSize = result.y;
length = collect_character_distribution(buffer, lSize, distribution);
reorganize_character_distribution(length, distribution, redistribution);
}
And
#include <stdio.h>
#include "character_distribution.h"
void main()
{
int length = 256; // you need to initialise this...
char distribution[length][2];
// No assignment needed here!:
character_distribution(length, distribution /* [length][2] - remove this! */);
int a;
for(a = 0; a < length; a++)
{
printf("%c\n", distribution[a][0]);
}
}
(Of course this relies on the various other functions you call performing as they are supposed to).
Change the signature to this:
char** character_distribution(int length, char redistribution[length][2])
You are returning a multidimensional array, not a character.
I have a large number of strings that I need to store in a character array and I need to be able to loop through all of the strings.
Furthermore, these strings won't be changing so I want the matrix to be permanent and preferably stored in a header file.
Can anyone point me in the right direction?
I'm working in C and don't know the best way to go about this.
Thanks!
Variable definitions in a header might not be such a good idea, consider alternatives:
// source.c contains
const char *const strings[] = {
"string1", "string2", NULL
};
// source.h contains
extern const char *const strings[];
// include source.h anywhere and loop through the strings like this:
for (const char *const *str = strings; *str != NULL; ++str)
// use *str
Try declaring a two level pointer:
#define NUMBER_OF_ROWS 10
#define MAX_NUMBER_OF_CHARS_IN_STRING 255
char *strings = (char**)calloc(NUMBER_OF_ROWS * sizeof(char));
const char copy_string[] = "default string";
for(int i = 0; i < NUMBER_OF_ROWS; i++)
{
strings[i] = (char*)calloc(MAX_NUMBER_OF_CHARS_IN_STRING);
}
for(int i = 0; i < NUMBER_OF_ROWS; i++)
{
strcpy(strings[i], copy_string);
}
This is assuming you are using ANSI C