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
Related
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.
Language: C
I am trying to program a C function which uses the header char *strrev2(const char *string) as part of interview preparation, the closest (working) solution is below, however I would like an implementation which does not include malloc... Is this possible? As it returns a character meaning if I use malloc, a free would have to be used within another function.
char *strrev2(const char *string){
int l=strlen(string);
char *r=malloc(l+1);
for(int j=0;j<l;j++){
r[j] = string[l-j-1];
}
r[l] = '\0';
return r;
}
[EDIT] I have already written implementations using a buffer and without the char. Thanks tho!
No - you need a malloc.
Other options are:
Modify the string in-place, but since you have a const char * and you aren't allowed to change the function signature, this is not possible here.
Add a parameter so that the user provides a buffer into which the result is written, but again this is not possible without changing the signature (or using globals, which is a really bad idea).
You may do it this way and let the caller responsible for freeing the memory. Or you can allow the caller to pass in an allocated char buffer, thus the allocation and the free are all done by caller:
void strrev2(const char *string, char* output)
{
// place the reversed string onto 'output' here
}
For caller:
char buffer[100];
char *input = "Hello World";
strrev2(input, buffer);
// the reversed string now in buffer
You could use a static char[1024]; (1024 is an example size), store all strings used in this buffer and return the memory address which contains each string. The following code snippet may contain bugs but will probably give you the idea.
#include <stdio.h>
#include <string.h>
char* strrev2(const char* str)
{
static char buffer[1024];
static int last_access; //Points to leftmost available byte;
//Check if buffer has enough place to store the new string
if( strlen(str) <= (1024 - last_access) )
{
char* return_address = &(buffer[last_access]);
int i;
//FixMe - Make me faster
for( i = 0; i < strlen(str) ; ++i )
{
buffer[last_access++] = str[strlen(str) - 1 - i];
}
buffer[last_access] = 0;
++last_access;
return return_address;
}else
{
return 0;
}
}
int main()
{
char* test1 = "This is a test String";
char* test2 = "George!";
puts(strrev2(test1));
puts(strrev2(test2));
return 0 ;
}
reverse string in place
char *reverse (char *str)
{
register char c, *begin, *end;
begin = end = str;
while (*end != '\0') end ++;
while (begin < --end)
{
c = *begin;
*begin++ = *end;
*end = c;
}
return str;
}
I'm reading in a line from a file (char by char, using fgetc()), where all fields(firstname, lastname, ...) are seperated by an ;. What I now want to do is create a char**, add all the chars to that and replace the ; by \0 so that I effectively get a list of all the fields.
Is that actually possibly? And when I create a char**, e.g. char ** buf = malloc(80) can I treat it like a one dimensional array? If the memory returned by malloc contiguous?
EDIT
Sry, meant to replace ; by \0, bot \n.
EDIT 2
This code should demonstrate what I intend to do (may clarify things a little):
int length = 80; // initial length char *buf = malloc(length); int num_chars = 0;
// handle malloc returning NULL
// suppose we already have a FILE pointer fp for (int ch = fgetc(fp); ch != EOF && ferror(fp) == 0; ch = fgetc(fp)) {
if (length == size) { // expand array if necessary
length += 80;
buf = realloc(buf, length);
// handle realloc failure
}
if (ch == ';') {
buf[num_chars] = '\0'; // replace delimiter by null-terminator
} else {
buf[num_chars] = ch; // else put char in buf
} }
// resize the buffer to chars read buf
= realloc(buf, num_chars);
// now comes the part where I'm quite unsure if it works / is possible
char **list = (char **)buf; // and now I should be able to handle it like a list of strings?
Yes, it's possible. Yes, you can treat it as a one dimensional array. Yes, the memory is contiguous.
But you probably want:
char ** fields = malloc(sizeof(char *) * numFields);
Then you can do:
// assuming `field` is a `char *`
fields[i++] = field;
It's not exactly possible as you describe it, but something similar is possible.
More specifically, the last line of your example char **list = (char **)buf; won't do what you believe. char **list means items pointed by *list will be of the type char*, but the content of *buf are chars. Hence it won't be possible to change one into another.
You should understand that a char ** is just a pointer, it can hold nothing by itself. But the char ** can be the start address of an array of char *, each char * pointing to a field.
You will have to allocate space for the char * array using a first malloc (or you also can use a static array of char * instead of a char**. You also will have to find space for every individual field, probably performing a malloc for each field and copying it from the initial buffer. If the initial buffer is untouched after reading, it would also be possible to use it to keep the field names, but if you just replace the initial ; by a \n, you'll be missing the trailing 0 string terminator, you can't replace inplace one char by two char.
Below is a simplified example of what can be done (removed malloc part as it does not add much to the example, and makes it uselessly complex, that's another story):
#include <stdio.h>
#include <string.h>
main(){
// let's define a buffer with space enough for 100 chars
// no need to perform dynamic allocation for a small example like this
char buf[100];
const char * data = "one;two;three;four;";
// now we want an array of pointer to fields,
// here again we use a static buffer for simplicity,
// instead of a char** with a malloc
char * fields[10];
int nbfields = 0;
int i = 0;
char * start_of_field;
// let's initialize buf with some data,
// a semi-colon terminated list of strings
strcpy(buf, data);
start_of_field = buf;
// seek end of each field and
// copy addresses of field to fields (array of char*)
for (i = 0; buf[i] != 0; i++){
if (buf[i] == ';'){
buf[i] = 0;
fields[nbfields] = start_of_field;
nbfields++;
start_of_field = buf+i+1;
}
}
// Now I can address fields individually
printf("total number of fields = %d\n"
"third field is = \"%s\"\n",
nbfields, fields[2]);
}
I now want to do is create a char**, add all the chars to that
You would allocate an array of char (char*) to store the characters, not an array of char* (char**).
And when I create a char*, e.g. char * buf = malloc(80) can I treat it like a one dimensional array? If the memory returned by malloc contiguous?
Yes, malloc always returns continguous blocks. Yes, you can treat it as single-dimensional an array of char* (with 80/sizeof char* elements). But you'll need to seperately allocate memory for each string you store in this array, or create another block for storing the string data, then use your first array to store pointers into that block.
(or something else; lots of ways to skin this cat)
It may be that Helper Method wants each of the "fields" written to a nul-terminated string. I cannot tell. You can do that with strtok(). However strtok() has problems - it destroys the original string "fed" to it.
#define SPLIT_ARRSZ 20 /* max possible number of fields */
char **
split( char *result[], char *w, const char *delim)
{
int i=0;
char *p=NULL;
for(i=0, result[0]=NULL, p=strtok(w, delim); p!=NULL; p=strtok(NULL, delim), i++ )
{
result[i]=p;
result[i+1]=NULL;
}
return result;
}
void
usage_for_split(void)
{
char *result[SPLIT_ARRSZ]={NULL};
char str[]="1;2;3;4;5;6;7;8;9;This is the last field\n";
char *w=strdup(str);
int i=0;
split(result, w, ";\n");
for(i=0; result[i]!=NULL; i++)
printf("Field #%d = '%s'\n", i, result[i]);
free(w);
}
I have a bunch of strings that look like:
'Hello1-FOO', 'Aello2-FOO', 'Bye1-BAR', 'Bye3-BAR', 'Hello22-FOO', 'Bye4-BAR', 'Welcome-BAR' ...
All of them are stored on a struct.
struct str {
char *strings;
}
...
struct str **t_str;
size_t j;
t_str = malloc(sizeof *t_str * 20);
for (j = 0; j < 20; j++)
t_str[j] = malloc(sizeof *t_str[j]);
...
t_str[0]->strings = "Hello1-FOO";
t_str[1]->strings = "Aello2-FOO";
....
What I would like to do is to display (sort) them by category, so they look similar to this:
FOO:
Hello1-FOO
Aello2-FOO
Hello22-FOO
BAR:
Bye4-BAR
Welcome-BAR
Bye1-BAR
Bye3-BAR
Basically group them by the token after the '-'
What would be a good way of doing this? Should I store them on a second struct after processing the string? Any idea will be appreciated. Thanks
Just use qsort. The following code makes some assumptions but you should be able to change it to suit your needs.
int categoryComparitor(const void * a, const void * b)
{
char *string1 = (char *)a;
char *string2 = (char *)b;
string1 = strrchr(string1, '-') + 1;
string2 = strrchr(string2, '-') + 1;
return strcmp(string1, string2);
}
{
...
char *strings[]; // Array of string pointers
int stringCount; // Holds current number of valid elements in strings.
...
qsort(strings, stringCount, sizeof(char *), categoryComparitor);
}
As David Thornley already pointed out, your struct isn't really defined well to handle this situation (well at all). Since your input is two separate logical pieces, you really want to define the struct accordingly -- containing two separate strings, one for each part of the input.
struct record {
char *category;
char *string;
};
Then you want to read each piece into one of those two strings:
record read_line(FILE *infile) {
char buffer1[128], buffer2[128];
fscanf(infile, "%[^-]-%s", buffer1, buffer2);
record ret;
ret.string = dupe_string(buffer1);
ret.category = dupe_string(buffer2);
return ret;
}
Then, to sort those records, you'll want to define a comparison function with the signature expected by qsort, that does a comparison on the category member:
int cmp(void *a, void *b) {
return strcmp(((record *)a)->category, ((record *)b)->category);
}
Then you'll sort your array of records using that comparison function.
Is it possible to have a (fixed) array which stores its elements in the read-only segment of the executable and not on the stack? I came up with this code but unfortunately it is very unflexible when it comes to adding, moving or deleting items. How do I verify that the strings are indeed stored in the read-only segment? I tried readelf -a file but it doesn't list the strings.
typedef struct {
int len;
int pos[100];
char data[500];
} FixedStringArray;
const FixedStringArray items = {
4,
{ 9, 14, 19, 24 },
"LongWord1Word2Word3Word4"
} ;
char* GetItem(FixedStringArray *array, int idx, int *len) {
if (idx >= array->len) {
/* Out of range */
*len = -1;
return NULL;
}
if (idx > 0) {
*len = array->pos[idx] - array->pos[idx - 1];
return & array->data[array->pos[idx - 1]];
}
*len = array->pos[idx];
return & array->data[0];
}
void PrintItem(FixedStringArray array, int idx) {
int len;
char *c;
int i = 0;
c = GetItem(&array, idx, &len);
if (len == -1) return;
while (i < len) {
printf("%c", *c);
*c++;
i++;
}
}
I am considering a script that automatically generates a struct for each array and uses the correct length for pos and data. Are there any concerns in terms of memory usage?
Or would it be better to create one struct (like above) to fit all strings?
I'm not sure I understand your question, but do you mean:
const char * const array[] = { "LongWord1", "Word2", "Word3", "Word4" };
This declares a constant array of pointers to constant characters.
OK, to avoid strlen, how about:
struct Str {
size_t len;
char *str;
};
#define STR(s) { sizeof(#s) - 1, #s }
const struct Str[] = { STR(LongWord1), STR(Word2), STR(Word3), STR(Word4) };
Can't your C compiler stick any/all literal strings into read-only memory (e.g. VC++ with string pooling enabled)? Or do you explicitly require them to be stored sequentially in that way?
This question is somewhat relevant:
String Literals
As pointed out, the storage of string literals in ROM/RAM is platform/implementation dependent, you should not make any predictions for that. Also using a script to read and create array of appropriate sizes and store them is quite undesirable. You should better go for dynamic memory.