How to pass array of char arrays to function by reference? - arrays

I want to initialize array of char arrays in a function:
void myFunction(char*** words)
{
int size = 3;
char** words_ = (char**) malloc(size * sizeof(char*));
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
*words = words_;
}
which I use in that way:
char** multiple_words;
myFunction(&multiple_words);
Is there any other way to write this code better/simpler?
(This code works BTW).

char** myFunction()
{
int size = 3;
char** words_ = (char**) malloc(size * sizeof(char*));
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
return words_;
}
char **words = myFunction();

You can simplify the malloc call itself a bit. You don't need to cast the result of malloc in C1, so that call could be simplified to
char** words_ = malloc(size * sizeof *words); // sizeof *words == sizeof (char *)
Always check the result of a malloc, calloc, or realloc call. Even though the likelihood of the request failing is small, it's not zero.
The words_ variable really serves no purpose, and at first glance looked like you were redeclaring the words function argument. It would be simpler to get rid of it entirely and just write
*words = malloc( sizeof **words * size ); // sizeof **words == sizeof (char *)
leaving us with
void myFunction(char*** words)
{
int size = 3;
*words = malloc(size * sizeof **words);
if ( *words )
{
for (int i=0; i< size; ++i)
{
// init each word words[i] with some value
}
}
}
At least as of the 1989 standard - if you're using an ancient K&R-era implementation or if you're compiling this code as C++, then a cast is required. However, if you're writing C++, then you shouldn't be using malloc anyway.

I would create abstractions depending on what I want to represent:
struct word {
char *letters;
};
struct sentence {
struct word *words;
};
// and then work with those abstractions:
int sentence_create(struct sentence *s) {
const size_t size = 3;
s->words = malloc(size * sizeof(*s->words));
if (s->words == NULL) goto ERR_WORDS;
s->words[0] = strdup("hello");
if (s->words[0] == NULL) goto ERR_0;
s->words[1] = strdup("world");
if (s->words[1] == NULL) goto ERR_1;
s->words[2] = NULL;
// success
return 0;
// goto error handling
free(s->words[1]);
ERR_1:
free(s->words[0]);
ERR_0:
free(s->words);
s->words = NULL;
ERR_WORDS:
return -ENOMEM;
}
int main() {
struct sentence sentence;
if (sentence_create(&sentence) != 0) {
fprintf(stderr, "Oh no!");
abort();
}
// TODO: sentence_destroy(&sentence) to free memory
}
Also see wiki.c2 Three Star Programmer

Not sure 100% whether it is easier or not:
typedef struct {
char **words;
} WordList;
void myFunc(WordList *wordList) {
...
wordList->words = malloc(numberOfWords * sizeof(char *));
// strSource : this string comes from somewhere in your code
...
for (int i = 0; i < numberOfWords; i++) {
int numberOfChars = strlen(strSource);
(wordList->words)[i] = malloc((numberOfChars + 1) * sizeof(char));
(wordList->words)[i][numberOfChars] = '\0';
...
strcpy((wordList->words)[i], strSource)
...
}
...
}
int main() {
WordList wordList;
...
myFunc(&wordList);
...
}

This is gonna get icky no matter how you write it.
A char** is fine to use for pointing at the first item in an array of char*, each pointing at a string of individual length.
It is best if the function can return a char**, but if that isn't possible, then...
We'd have to return a char** through parameters, means we have to write char***. Three levels of indirection is always questionable, but this specific case is about the only valid use for it. Or the lesser evil at least, since...
Some makeshift struct wrapper that does nothing but hiding away the *** isn't making the code any better or more readable. That's very similar to hiding pointers behind typedef, not recommended.
The least messy way to write that might be something like this:
void heard (char*** word, size_t size)
{
char** the_word = malloc( sizeof(char*[size]) );
for(size_t i=0; i<size; i++)
{
const char* str = "bird"; // some random data from somewhere
the_word[i] = malloc (sizeof str); // allocate room for individual strings
strcpy(the_word[i], str);
}
*word = the_word;
}
Then call it as:
char** word;
heard(&word, 3);
for(size_t i=0; i<3; i++)
{
puts(word[i]);
}
The most proper solution is probably to use a complete string container class which handles all of this for you. Then you'd just declare arrays of strings and don't worry about all the details of allocating things manually.

Related

Function to modify dynamically allocated two dimensional array of char*

So, here's my logic:
This is some text:
char *text;
Then this is array of texts:
char **arr;
Then array of these arrays is:
char ***arr2d;
And if I want a function to modify it, it needs to accept it as:
char ****arr2d;
And within the function use it as:
*arr2d = (e.g. allocate);
So if I want to create 2D array like this and make the first row, first column contain just a letter 'a', then why does this not work?
#define COLUMNS 7
void loadTable(char ****table)
{
*table = (char ***) malloc(sizeof(char**));
if (!*table) {
printf("Allocation error for table rows.");
return;
}
*table[0] = (char**) malloc(COLUMNS * sizeof(char*));
if (!*table[0]) {
printf("Allocation error for table columns.");
return;
}
*table[0][0] = (char*) malloc(2 * sizeof(char));
*table[0][0][0] = (char)(97);
*table[0][0][1] = '\0';
}
int main()
{
char ***table;
loadTable(&table);
return 0;
}
You would need only 3 *** to do what you describe, not 4 ****. Be aware, there are methods to allow you to avoid excessive depth in terms of arrays of arrays of strings. And there are also good reasons to avoid excessively deep orders of arrays, not the least is the need to free(.) everything you allocate. That means exactly one call to free(.) for each and every call to [m][c][re]alloc(.).
But to address your question...
In general, to create new memory for a single array of a previously allocated memory, you could use a function prototyped as:
char * ReSizeBuffer(char **str, size_t origSize);
Where if say the previously allocated buffer were created as:
char *buf = calloc(origSize, 1);
...the usage could look like:
char *tmp = {0};
tmp = ReSizeBuffer(&buf, newSize); //see implementation below
if(!tmp)
{
free(buf);
return NULL;
}
buf = tmp;
///use new buf
...
Then if this works for a single array of char, then the prototype for allocating new memory for a previously allocated array of strings might look like this:
char ** ReSizeBuffer(char ***str, size_t numArrays, size_t strLens);
Where if say the previously allocated 2D buffer were created as:
char **buf = Create2DStr(size_t numStrings, size_t maxStrLen); //see implementation below
...the usage could look like:
char **tmp = {0};
tmp = ReSizeBuffer(&buf, numStrings, maxStrLen);
if(!tmp)
{
free(buf);
return NULL;
}
buf = tmp;
///use new buf
...
Implementations:
Implementation of ReSizeBuffer. This must be expanded if you desire to implement the second prototype:
char * ReSizeBuffer(char **str, size_t size)
{
char *tmp={0};
if(!(*str)) return NULL;
if(size == 0)
{
free(*str);
return NULL;
}
tmp = (char *)realloc((char *)(*str), size);
if(!tmp)
{
free(*str);
return NULL;
}
*str = tmp;
return *str;
}
Implementation of Create2DStr might look like this:
char ** Create2DStr(size_t numStrings, size_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
I just stumbled upon this old question of mine and spotted the problem immediately. Here is the answer:
The number of asterisks is actually correct, the problem is operator evaluation. Specifically, all lines of code of this form:
*table[0]
should have been written as:
(*table)[0]

Overlaying array of strings over char array

I am working a function that needs to be re-entrant - the function is given a memory buffer as an argument and should use such buffer for all its memory needs. In other words, it can't use malloc, but rather should draw the memory the supplied buffer.
The challenge that I ran into is how to overlay an array of strings over a char array of given size (the buffer is supplied as char *), but my result is array of strings (char **).
Below is a repro:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 100
#define INPUT_ARRAY_SIZE 3
char *members[] = {
"alex",
"danny",
"max"
};
int main() {
// this simulates a buffer that is presented to my func
char *buffer = malloc(BUFFER_SIZE);
char *orig = buffer;
memset(buffer, NULL, BUFFER_SIZE);
// pointers will be stored at the beginning of the buffer
char **pointers = &buffer;
// strings will be stored after the pointers
char *strings = buffer + (sizeof(char *) * INPUT_ARRAY_SIZE);
for(int i = 0; i < INPUT_ARRAY_SIZE; i++) {
strncpy(strings, members[i], (strlen(members[i]) + 1));
// Need to store pointer to string in the pointers section
// pointers[i] = strings; // This does not do what I expect
strings += ((strlen(members[i]) + 1));
}
for (int i=0; i < BUFFER_SIZE; i++) {
printf("%c", orig[i]);
}
// Need to return pointers
}
With the problematic line commented out, the code above prints:
alex danny max
However, I need some assistance in figuring out how to write addresses of the strings at the beginning.
Of course, if there an easier way of accomplishing this task, please, let me know.
Here take a look at this.
/* conditions :
*
* 'buffer' should be large enough, 'arr_length','arr' should be valid.
*
*/
char ** pack_strings(char *buffer, char * arr[], int arr_length)
{
char **ptr = (char**) buffer;
char *string;
int index = 0;
string = buffer + (sizeof(char *) * (arr_length+1)); /* +1 for NULL */
while(index < arr_length)
{
size_t offset;
ptr[index] = string;
offset = strlen(arr[index])+1;
strcpy(string,arr[index]);
string += offset;
++index;
}
ptr[index] = NULL;
return ptr;
}
usage
char **ptr = pack_strings(buffer,members,INPUT_ARRAY_SIZE);
for (int i=0; ptr[i] != NULL; i++)
puts(ptr[i]);

Using an array of structures with call by reference

Here is my problem: I have to make this program for school and I spent the last hour debugging and googling and haven't found an answer.
I have an array of structures in my main and I want to give that array to my function seteverythingup (by call by reference) because in this function a string I read from a file is split up, and I want to write it into the structure but I always get a SIGSEV error when strcpy with the struct array.
This is my main:
int main(int argc, char *argv[])
{
FILE* datei;
int size = 10;
int used = 0;
char line[1000];
struct raeume *arr = (raeume *) malloc(size * sizeof(raeume*));
if(arr == NULL){
return 0;
}
if(argc < 2){
return 0;
}
datei = fopen(argv[1], "rt");
if(datei == NULL){
return 0;
}
fgets(line,sizeof(line),datei);
while(fgets(line,sizeof(line),datei)){
int l = strlen(line);
if(line[l-1] == '\n'){
line[l-1] = '\0';
}
seteverythingup(&line,arr,size,&used);
}
ausgabeunsortiert(arr,size);
fclose(datei);
return 0;
}
and this is my function:
void seteverythingup(char line[],struct raeume *arr[], int size,int used)
{
char *token,raumnummer[5],klasse[6];
int tische = 0;
const char c[2] = ";";
int i=0;
token = strtok(line, c);
strcpy(raumnummer,token);
while(token != NULL )
{
token = strtok(NULL, c);
if(i==0){
strcpy(klasse,token);
}else if(i==1){
sscanf(token,"%d",&tische);
}
i++;
}
managesize(&arr[size],&size,used);
strcpy(arr[used]->number,raumnummer);
strcpy(arr[used]->klasse,klasse);
arr[used]->tische = tische;
used++;
}
Edit: Since there is more confusion I wrote a short program that works out the part you are having trouble with.
#include <cstdlib>
struct raeume {
int foo;
int bar;
};
void seteverythingup(struct raeume *arr, size_t len) {
for (size_t i = 0; i < len; ++i) {
arr[i].foo = 42;
arr[i].bar = 53;
}
}
int main() {
const size_t size = 10;
struct raeume *arr = (struct raeume*) malloc(size * sizeof(struct raeume));
seteverythingup(arr, size);
return 0;
}
So basically the signature of your functions is somewhat odd. Malloc returns you a pointer to a memory location. So you really dont need a pointer to an array. Just pass the function the pointer you got from malloc and the function will be able to manipulate that region.
Original Answer:
malloc(size * sizeof(raeume*));
This is probably the part of the code that gives you a hard time. sizeof returns the size of a type. You ask sizeof how many bytes a pointer to you raeume struct requires. what you probably wanted to do is ask for the size of the struct itself and allocate size times space for that. So the correct call to malloc would be:
malloc(size * sizeof(struct raeume));

Allocating and Freeing pointer to pointer

I'm attempting to pass a pointer to a pointer (char**) into a function that will initialize it, and then pass it into another function that will free the memory, however I'm getting seg faults on the freeing which leads me to believe my allocation is going wrong.
Valgrind is reporting use of uninitalized value at this line. tmp[i] is pointing to 0x0.
if(tmp[i]) free((char*)tmp[i]);
Here is the code (this is only test code)
void
alloc_strings(char ***test, int count)
{
char **tmp = *test;
tmp = malloc(count * sizeof(char*));
int i;
for(i = 0; i < count; i++) {
tmp[i] = malloc(6);
strcpy(tmp[i],"Hello");
}
}
void
free_strings(char ***test, int count)
{
char **tmp = *test;
int i;
for(i = 0; i < count; i++) {
if(tmp[i]) free((char*)tmp[i]);
}
if(tmp)
free(tmp);
}
And the invocation:
int
main(int argc, char **argv)
{
char **test;
alloc_strings(&test, 10);
free_strings(&test, 10);
return 0;
}
I have been playing around with this for a while, reading up on pointers etc however can't get my head around the issue. Any thoughts greatly appreciated!
You need to assign to *test, not to assign from it. How about:
void
alloc_strings(char ***test, int count)
{
char **tmp = malloc(count * sizeof *tmp);
/*...*/
*test = tmp;
}
In the code example,
alloc_strings(char ***test, int count)
{
char **tmp = *test;
*test should have some space to store a pointer to char ** which currently is not allocated. Hence, if the example is as this
char** array[1];
alloc_strings(&array[0], 7);
I feel that the code will work.

How to allocate and deallocate heap memory for 2D array?

I'm used to PHP, but I'm starting to learn C. I'm trying to create a program that reads a file line by line and stores each line to an array.
So far I have a program that reads the file line by line, and even prints each line as it goes, but now I just need to add each line to an array.
My buddy last night was telling me a bit about it. He said I'd have to use a multidimensional array in C, so basically array[x][y]. The [y] part itself is easy, because I know the maximum amount of bytes that each line will be. However, I don't know how many lines the file will be.
I figure I can make it loop through the file and just increment an integer each time and use that, but I feel that there might be a more simple way of doing it.
Any ideas or even a hint in the right direction? I appreciate any help.
To dynamically allocate a 2D array:
char **p;
int i, dim1, dim2;
/* Allocate the first dimension, which is actually a pointer to pointer to char */
p = malloc (sizeof (char *) * dim1);
/* Then allocate each of the pointers allocated in previous step arrays of pointer to chars
* within each of these arrays are chars
*/
for (i = 0; i < dim1; i++)
{
*(p + i) = malloc (sizeof (char) * dim2);
/* or p[i] = malloc (sizeof (char) * dim2); */
}
/* Do work */
/* Deallocate the allocated array. Start deallocation from the lowest level.
* that is in the reverse order of which we did the allocation
*/
for (i = 0; i < dim1; i++)
{
free (p[i]);
}
free (p);
Modify the above method. When you need another line to be added do *(p + i) = malloc (sizeof (char) * dim2); and update i. In this case you need to predict the max numbers of lines in the file which is indicated by the dim1 variable, for which we allocate the p array first time. This will only allocate the (sizeof (int *) * dim1) bytes, thus much better option than char p[dim1][dim2] (in c99).
There is another way i think. Allocate arrays in blocks and chain them when there is an overflow.
struct _lines {
char **line;
int n;
struct _lines *next;
} *file;
file = malloc (sizeof (struct _lines));
file->line = malloc (sizeof (char *) * LINE_MAX);
file->n = 0;
head = file;
After this the first block is ready to use. When you need to insert a line just do:
/* get line into buffer */
file.line[n] = malloc (sizeof (char) * (strlen (buffer) + 1));
n++;
When n is LINE_MAX allocate another block and link it to this one.
struct _lines *temp;
temp = malloc (sizeof (struct _lines));
temp->line = malloc (sizeof (char *) * LINE_MAX);
temp->n = 0;
file->next = temp;
file = file->next;
Something like this.
When one block's n becomes 0, deallocate it, and update the current block pointer file to the previous one. You can either traverse from beginning single linked list and traverse from the start or use double links.
There's no standard resizable array type in C. You have to implement it yourself, or use a third-party library. Here's a simple bare-bones example:
typedef struct int_array
{
int *array;
size_t length;
size_t capacity;
} int_array;
void int_array_init(int_array *array)
{
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_free(int_array *array)
{
free(array->array);
array->array = NULL;
array->length = 0;
array->capacity = 0;
}
void int_array_push_back(int_array *array, int value)
{
if(array->length == array->capacity)
{
// Not enough space, reallocate. Also, watch out for overflow.
int new_capacity = array->capacity * 2;
if(new_capacity > array->capacity && new_capacity < SIZE_T_MAX / sizeof(int))
{
int *new_array = realloc(array->array, new_capacity * sizeof(int));
if(new_array != NULL)
{
array->array = new_array;
array->capacity = new_capacity;
}
else
; // Handle out-of-memory
}
else
; // Handle overflow error
}
// Now that we have space, add the value to the array
array->array[array->length] = value;
array->length++;
}
Use it like this:
int_array a;
int_array_init(&a);
int i;
for(i = 0; i < 10; i++)
int_array_push_back(&a, i);
for(i = 0; i < a.length; i++)
printf("a[%d] = %d\n", i, a.array[i]);
int_array_free(&a);
Of course, this is only for an array of ints. Since C doesn't have templates, you'd have to either put all of this code in a macro for each different type of array (or use a different preprocessor such as GNU m4). Or, you could use a generic array container that either used void* pointers (requiring all array elements to be malloc'ed) or opaque memory blobs, which would require a cast with every element access and a memcpy for every element get/set.
In any case, it's not pretty. Two-dimensional arrays are even uglier.
Instead of an array here, you could also use a linked list, The code is simpler, but the allocation is more frequent and may suffer from fragmentation.
As long as you don't plan to do much random access (Which is O(n) here), iteration is about as simple as a regular array.
typedef struct Line Line;
struct Line{
char text[LINE_MAX];
Line *next;
};
Line *mkline()
{
Line *l = malloc(sizeof(Line));
if(!l)
error();
return l;
}
main()
{
Line *lines = mkline();
Line *lp = lines;
while(fgets(lp->text, sizeof lp->text, stdin)!=NULL){
lp->next = mkline();
lp = lp->next;
}
lp->next = NULL;
}
If you are using C you will need to implement the resizing of the array yourself. C++ and the SDL has this done for you. It is called a vector. http://www.cplusplus.com/reference/stl/vector/
While a multidimensional array can solve this problem, a rectangular 2D array would not really be the natural C solution.
Here is a program that initially reads the file into a linked list, and then allocates a vector of pointers of the right size. Each individual character does then appear as array[line][col] but in fact each row is only as long as it needs to be. It's C99 except for <err.h>.
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct strnode {
char *s;
struct strnode *next;
} strnode;
strnode *list_head;
strnode *list_last;
strnode *read1line(void) {
char space[1024];
if(fgets(space, sizeof space, stdin) == NULL)
return NULL;
strnode *node = malloc(sizeof(strnode));
if(node && (node->s = malloc(strlen(space) + 1))) {
strcpy(node->s, space);
node->next = NULL;
if (list_head == NULL)
list_head = node;
else
list_last->next = node;
list_last = node;
return node;
}
err(1, NULL);
}
int main(int ac, char **av) {
int n;
strnode *s;
for(n = 0; (s = read1line()) != NULL; ++n)
continue;
if(n > 0) {
int i;
strnode *b;
char **a = malloc(n * sizeof(char *));
printf("There were %d lines\n", n);
for(b = list_head, i = 0; b; b = b->next, ++i)
a[i] = b->s;
printf("Near the middle is: %s", a[n / 2]);
}
return 0;
}
You can use the malloc and realloc functions to dynamically allocate and resize an array of pointers to char, and each element of the array will point to a string read from the file (where that string's storage is also allocated dynamically). For simplicity's sake we'll assume that the maximum length of each line is less than M characters (counting the newline), so we don't have to do any dynamic resizing of individual lines.
You'll need to keep track of the array size manually each time you extend it. A common technique is to double the array size each time you extend, rather than extending by a fixed size; this minimizes the number of calls to realloc, which is potentially expensive. Of course that means you'll have to keep track of two quantities; the total size of the array and the number of elements currently read.
Example:
#define INITIAL_SIZE ... // some size large enough to cover most cases
char **loadFile(FILE *stream, size_t *linesRead)
{
size_t arraySize = 0;
char **lines = NULL;
char *nextLine = NULL;
*linesRead = 0;
lines = malloc(INITIAL_SIZE * sizeof *lines);
if (!lines)
{
fprintf(stderr, "Could not allocate array\n");
return NULL;
}
arraySize = INITIAL_SIZE;
/**
* Read the next input line from the stream. We're abstracting this
* out to keep the code simple.
*/
while ((nextLine = getNextLine(stream)))
{
if (arraySize <= *linesRead)
{
char **tmp = realloc(lines, arraysSize * 2 * sizeof *tmp);
if (tmp)
{
lines = tmp;
arraySize *= 2;
}
}
lines[(*linesRead)++] = nextLine;
)
return lines;
}

Resources