I want to know how to create a dynamic array of 2 strings per array. And I'm not sure how. I know how to create an array of strings, but not one of "n" dimensions, and i want to know how.
Here are some parts of my code, which is just currently an array of strings:
First I declared my array inside an struct:
typedef struct{
char bloqueCedula[7];
short bloqueDia;
char **bloqueLibrosPrestados;//This is the array i want to modify
}RegistroControl;
then I initialize it on my first registration:
void primerRegistro(RegistroArchivo regArch, RegistroControl *regControl) {
strcpy(regControl->bloqueCedula, regArch.cedula);
regControl->bloqueDia = regArch.dia;
regControl->bloqueLibrosPrestados = malloc(cont * sizeof(regControl->bloqueLibrosPrestados));
regControl->bloqueLibrosPrestados[0] = malloc(7 * sizeof(char));
strcpy(regControl->bloqueLibrosPrestados[0], regArch.codigoLibro);
imprimirCabecera();
//printf("%s\n", regControl->bloqueLibrosPrestados[cont-1]);
}
In the code above I made each string of a length 7, because I already know the length of what I need to copy on it, which is 6.
This is how I kept making it grow:
void procesarRegistro(RegistroArchivo regArch, RegistroControl *regControl) {
cont++;
regControl->bloqueLibrosPrestados = realloc(regControl->bloqueLibrosPrestados,cont * sizeof(regControl->bloqueLibrosPrestados));
regControl->bloqueLibrosPrestados[cont-1] = malloc(7 * sizeof(char));
strcpy(regControl->bloqueLibrosPrestados[cont-1], regArch.codigoLibro);
printf("%s\n", regControl->bloqueLibrosPrestados[cont-2]);
}
I want to know how to add another string of 2 length next to the one that is 7 length. This codes are parts of a code that reads from a file until it reaches EOF, that's why I used a counter which is "cont".
You have a char**.
Suppose a. Allocate some memory to a.
a= malloc(sizeof(char*)*10);
if( a == NULL)
{
fprintf(stderr,"%s","error in malloc");
exit(1);
}
Now for each of the position of a you do the same thing only this time it is for char.
a[i]= malloc(sizeof(char)*100);
if( a[i] == NULL)
{
//...
}
Free them when done.
free(a[i]); //for each i.
free(a);
a=NULL;
Now this is 2 dimension
Now I don't know when you need more than this. This can always be extended.
char *** aa; But it is not needed. {read this}
If you need it then you should think over your data representation.
Theoretical idea for N dimensional strings
For n dimensional you can do this:-
char **...n...** complicated= malloc(sizeof(char**...n...>**)*N1);
// malloc check
for(int i=0;i<N1;i++)
complicated[i]= malloc(sizeof(char**...(n-1)...**)*N2);
...
Related
I'm writing a card game program and currently, I'm trying to create global char* arrays to represent a player 1 hand and a player 2 hand. I want to use malloc if the arrays have not been initialized yet and realloc later in the game in order to deal into them again. I have a function called dealCards which takes the deck of cards and the number to deal out as arguments. Within I want to be able to reallocate memory to the player arrays with each call depending on the number of cards to deal. So far I tried to test if the arrays were NULL and to use malloc and if not, use realloc, but I got errors of my conditions always equalling false and true therefore the would not test correctly. My current approach which still isn't working is to malloc a single char in the first index of each array, then reallocate in my function. But this is returning an error that reallocation has not occurred. So essentially how can I dynamically create two char* arrays, and then reallocate as needed on a function call?
Deal cards function
int dealCards(char *(*deck)[13], int numCardsToDeal)
{
char *player1Hand = realloc(player1Hand, numCardsToDeal / 2 * (4 * sizeof(char)));
char *player2Hand = realloc(player2Hand, numCardsToDeal / 2 * (4 * sizeof(char)));
//If number of cards passed in is greater than whats left in deck
if (numCardsToDeal > cardsRemaining)
{
printf("Number of cards to deal exceeds remaining deck. Remaining deck will be dealt.");
numCardsToDeal = cardsRemaining;
}
for (int i = 0; i < numCardsToDeal;)
{
player1Hand[i] = *deck[placeInDeck / 13][i];
printf("%c", player1Hand[i]);
i++;
if (i == numCardsToDeal)
{
break;
}
player2Hand[i] = *deck[placeInDeck / 13][i];
printf("%c", player2Hand[i]);
i++;
}
return numCardsToDeal;
}
My current attempt at initially using malloc
char **player1Hand;
char **player2Hand;
void initializePlayers(void)
{
char **player1Hand = malloc(sizeof(*player1Hand));
char **player2Hand = malloc(sizeof(*player2Hand));
for (int i = 0; i < 1; i++)
{
player1Hand[i] = malloc(sizeof(char));
player2Hand[i] = malloc(sizeof(char));
}
}
If any more info is needed please let me know, thanks.
I'm working on a minisql code in C and i having some issues to allocate array of strings. I made a function called "alocaString" to do this (bc i'm using that a lot), but i don't think is working.
When the code reaches the line "strncpy(lista[qtnPalavras], splitStr, 100);" in the function "listaPalavras" (that have the purpose of split a string in different types of characters) a file named "strcpy-avx2.S" is created, one of the arguments of that function (**lista) is allocated with "alocaString" so i think the problem is in that function.
I already try to use valgrind and shows "is used uninitialized in this function [-Werror=uninitialized]" to all arrays of strings that i tried to use on that function, but i'm initializing them inside of the function
int alocaString (char **string, int tamanho, int posicoes){
string = malloc (posicoes * sizeof(char*));
for (int i = 0; i < posicoes; i++){
string [i] = malloc (tamanho * sizeof(char));
if (string[i] == NULL){return 0;}
}
return **string;
}
void desalocaString (char **string, int posicoes){
for (int i = 0; i < (posicoes); i++){
free (string[i]);
}
free (string);
}
int listaPalavras(char *entrada, char **lista, char *separador){ // lista as palavras
char *splitStr;
int qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, 100);
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
I assume that you are using these functions like this:
alocaString(lista, tamanho, posicoes);
listaPalavras(some_string, lista, some_delimiters);
desalocaString(arr);
Even without looking at the code, it seems logically wrong to allocate an array of strings first and then populate it if you do not already know how many strings it will need to fit. If you happen to allocate an array of n strings, but your listaPalavras() functions splits the provided string into n+1 or more substrings, you're going to overflow your previously allocated array. Nonetheless, this can be done taking the appropriate precautions, like carrying around sizes and checking them to avoid overflow.
The only sane way to achieve what you want is therefore to either (A) count the number of delimiters in the string first to know in advantage how many pointers you will need or (B) dynamically allocate the needed amount in listaPalavras() while splitting. You seem to be going with something similar to option A, but your code is flawed.
The desalocaString() is the only function that seems correct.
A correct implementation of alocaString() would return the allocated array (or NULL in case of failure), but you are returning **string which is just the first character of the first string. Needless to say, this does not make much sense. You don't need to take a char ** parameter, just the sizes. Secondly, in case of failure of any of the calls to malloc() you should free the previously allocated ones before returning NULL.
char **alocaString (unsigned tamanho, unsigned posicoes) {
char **lista = malloc(posicoes * sizeof(char*));
if (lista == NULL)
return NULL;
for (unsigned i = 0; i < posicoes; i++) {
lista[i] = malloc(tamanho * sizeof(char));
if (lista[i] == NULL) {
for (unsigned j = 0; j < i; j++)
free(lista[j]);
free(lista);
return NULL;
}
}
return lista;
}
As per listaPalavras(), which has the job of splitting the given string into other strings and copying them into the previously allocated array, to avoid overflowing the given array of strings you will need to also provide its length as well as the length of the previously allocated strings as argument (let's call them posicoes and tamanho like for the above function). Moreover, strncpy() will not add a NUL-terminator (\0) to the destination string if it is not found in the source string within the first n characters (n being the third argument), so you will need to add it yourself to make sure your strings are correctly terminated.
unsigned listaPalavras(const char *entrada, char *separador, char **lista, unsigned posicoes, unsigned tamanho) {
char *splitStr;
unsigned qtnPalavras = 0;
splitStr = strtok(entrada, separador);
while (qtnPalavras < posicoes && splitStr != NULL){
strncpy(lista[qtnPalavras], splitStr, tamanho);
lista[qtnPalavras][tamanho - 1] = '\0';
qtnPalavras++;
splitStr = strtok(NULL, separador);
}
return qtnPalavras;
}
Finally the code of the caller should look something like this:
char **lista;
unsigned tamanho = 100;
unsigned posicoes = 10;
unsigned palavras;
lista = alocaString(tamanho, posicoes);
if (lista == NULL) {
// handle the error somehow
}
palavras = listaPalavras(YOUR_STRING, YOUR_DELIMITERS, lista, posicoes, tamanho);
desalocaString(lista);
This should work fine, however you are limited by the fact that:
You cannot know beforehand the number of substrings that strtok() will find.
You cannot know beforehand the length of any of those substrings.
Therefore, allocating the needed lista dynamically inside listaPalavras() would make more sense.
Finally, as a side note, the names of your functions are misleading: if you need to allocate an array of strings, you might want to choose a better name than alocaString() which seems to imply that you are allocating a single string. Maybe alocaLista() and dealocaLista() would be better choices.
Recently I was pondering over this question: how to make an easier way to iterate over an array of pointer in C.
If I create an array of string in C, it should look like this right?
int size = 5;
char ** strArr = (char **) malloc(sizeof(char *) * size);
if (strArr == NULL) return;
But the problem is, when you want to iterate over this array for some reason (like printing all values inside it), you have to keep track of its current size, storing in another variable.
That's not a problem, but if you create lots of arrays, you have to keep track of every single one of their sizes inside the code. If you pass this array to another function, you must pass its size as well.
void PrintValues (char ** arr, int size) {
for (int i = 0; i < size; i++)
printf("%s\n", arr[i]);
}
But when iterating over a string, it's different. You have the '\0' character, which specifies the end of the string. So, you could iterate over a string like this, with not need to keep its size value:
char * str = (char *) malloc(sizeof(char) * 4);
str[0] = 'a';
str[1] = 'b';
str[2] = 'c';
str[3] = '\0';
for (int i = 0; str[i] != '\0'; i++)
printf("%c", str[i]);
printf("\n");
Now my question:
Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
char ** strArr = (char **) malloc(sizeof(char *) * (5 +1);
if (strArr == NULL) return;
strArr[0] = PseudoFunc_NewString("Car");
strArr[1] = PseudoFunc_NewString("Car#1");
strArr[2] = PseudoFunc_NewString("Car#2");
strArr[3] = PseudoFunc_NewString("Tree");
strArr[4] = PseudoFunc_NewString("Tree#1");
strArr[5] = NULL; // Stop iteration here as next element is not allocated
Then I could use the NULL pointer to control the iterator:
void PrintValues (char ** arr) {
for (int i = 0; arr[i] != NULL; i++)
printf("%s\n", arr[i]);
}
This would help me to keep the code cleaner, though it would consume more memory as a pointer size is larger than a integer size.
Also, when programming with event-based libraries, like Gtk, the size values would be released from the stack at some point, so I would have to create a pointer to dynamically store the size value for example.
In cases like this, it ok to do this? Or is it considered something bad?
Is this technique only used with char pointers because char type has a size of only 1 byte?
I miss having a foreach iterator in C...
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
This is ok, the final NULL is called a sentinel value and using one is somewhat common practice. This is most often used when you don't even know the size of the data for some reason.
It is however, not the best solution, because you have to iterate over all the data to find the size. Solutions that store the size separately are much faster. An arrays of structs for example, containing both size and data in the same place.
Now my question: Is it ok or morally right to allocate +1 unit in an array of pointers to maintain its tail as NULL?
In C this is quite a common pattern, and it has a name. You're simply using a sentinel value.
As long as your list can not contain null pointers normally this is fine. It is a bit error-prone in general however, then again, that's C for you.
It's ok, and is a commonly used pattern.
As an alternative you can use a struct, in there you can create a size variable where you can store the current size of the array, and pass the struct as argument. The advantage is that you don't need to iterate through the entire array to know its size.
Example:
Live demo
#include <stdlib.h>
#include <stdio.h>
typedef struct
{
char **strArr;
int size;
} MyStruct;
void PrintValues(MyStruct arr) //pass the struct as an argument
{
for (int i = 0; i < arr.size; i++) //use the size passed in the struct
printf("%s\n", arr.strArr[i]);
}
int main()
{
// using the variable to extract the size, to avoid silent errors
// also removed the cast for the same reason
char **strArr = malloc(sizeof *strArr * 5);
if (strArr == NULL) return EXIT_FAILURE;
strArr[0] = "Car";
strArr[1] = "Car#1";
strArr[2] = "Car#2";
strArr[3] = "Tree";
strArr[4] = "Tree#1";
MyStruct strt = { strArr, 5 }; // initialize the struct
PrintValues(strt); //voila
free(strArr); // don't forget to free the allacated memory
return EXIT_SUCCESS;
}
This allows for direct access to an index with error checking:
// here if the array index exists, it will be printed
// otherwise no, allows for O(1) access error free
if(arr.size > 6){
printf("%s\n", arr.strArr[6]);
}
This question already has answers here:
C dynamically growing array
(10 answers)
Closed 6 years ago.
Can anyone explain to me the easiest way to create dynamically a 2D string array with stable second dimension? I've got a txt file with some strings in it and I want to transfer this txt to an array. So I want to associate the txt line number with the first dimension and the string itself with the second dimension. The second dimension is the number of characters in every row (which is stable because every line in the txt has a certain syntax) So if I have in my txt:
hello how (newline)
are youuu
*(I wrote youuu because as I said, every line has the same number of characters).
I want something like:
array[0]["hello how"],
array[1]["are youuu"]
Non numerical keys are not allowed in C. You're trying to do some PHP and JavaScript nonsense in a language that only works with numbers.
But, with C there is always 2 roads to hell.
char *lookup_key(int index, char *key) { ... }
printf(lookup_key(0, "hello how"));
If you know the length of the strings and how many you have, you can configure the array like this
char strings[numLines][strLen+1];
you can then access the array like this
strcpy(strings[1], "test2");
If you don't know anything beforehand, you need a pointer to pointer array and then use malloc to allocate space as the array grow, free when you are done.
dynamic in C implies you will need to use one of [c][m]alloc to create memory for your strings. And 2D implies an array of char arrays. Assuming you know the number of strings and the longest string needed, the following will create memory to contain them:
char ** Create2DStr(ssize_t numStrings, ssize_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;
}
The following will free the memory created above:
void free2DStr(char ** a, ssize_t numStrings)
{
int i;
for(i=0;i<numStrings; i++)
{
if(a[i]) free(a[i]);
}
free(a);
}
These can be called like this:
...
char **strArray = {0};
strArray = Create2DStr(10, 20);
//Use strArray...
free2DStr(10);
Giving 10 arrays, each able to contain 20 char, plus a NULL. (The + 1 after maxStrLen provides the extra space for the NULL).
If you want to save each line of the file as a row in the array, use a 2D array of char:
char fileContents[NUM_LINES][LINE_LENGTH + 1]; // +1 for zero terminator
If you don't know how many lines you have up front, you'll need to do some memory management. First, you'll need to allocate an initial extent:
#define INITIAL_EXTENT 20 // or some good starting point
char (*fileContents)[LINE_LENGTH + 1] = malloc( sizeof *fileContents * INITIAL_EXTENT );
if ( !fileContents )
{
// malloc failed; fatal error
fprintf( stderr, "FATAL: could not allocate memory for array\n" );
exit( EXIT_FAILURE );
}
size_t numRows = INITIAL_EXTENT; // number of rows in array
size_t rowsRead = 0; // number of rows containing data
As you read from the file, you'll check to make sure you have room in the array; if you don't, you'll need to extend the array with a realloc call, which is a potentially expensive operation. A common technique is to double the size of the array each time you extend it - that minimizes the total number of realloc calls. The risk is some internal fragmentation if you double the array size because you need just one more row, but that's probably something you can analyze around:
char tmpBuf[LINE_LENGTH + 2]; // account for newline in input buffer
while ( fgets( tmpBuf, sizeof tmpBuf, inputFile ) )
{
/**
* Check to see if you have any room left in your array; if not,
* you'll need to extend it. You'll probably want to factor this
* into its own function.
*/
if ( rowsRead == numRows )
{
/**
* Use a temporary variable for the result of realloc in case of failure
*/
char (*tmp)[LINE_LENGTH + 1] =
realloc( fileContents, sizeof *fileContents * ( 2 * numRows ) );
if ( !tmp )
{
/**
* realloc failed - we couldn't extend the array any more.
* Break out of the loop.
*/
fprintf( stderr, "ERROR: could not extend fileContents array - breaking out of loop\n" );
break;
}
/**
* Otherwise, set fileContents to point to the new, extended buffer
* and update the number of rows.
*/
fileContents = tmp;
numRows *= 2;
}
// strip the newline from the input buffer
char *newline = strchr( tmpBuf, '\n' );
if ( newline )
*newline = 0;
strcpy( fileContents[rowsRead++], tmpBuf );
}
I am having a bit of trouble because I am new to C and am not even sure if what I want to do is possible.
I am passing an array called args into a function. Within the function I am also creating a 2D array called arrayOfArgs. What I want to do is to put certain values from args into specific locations in the 2D array called arrayOfArgs.
This is my code so far:
int do_command(char **args){
//this is usually a changing variable depending on the situation, but I've hard coded it to make sense
int commands = 3;
char **arrayOfArgs[commands][10];
//counts which column in arrayOfArgs we are on
int commandNum = 0;
//Counts which part of a command we are on
int count = 0;
//Array Counters
int i = 0;
int j;
//Go through args until we reach the end
while (args[i] != NULL){
if(!strcmp(args[i], "|")){
arrayOfArgs[commandNum][count] = args[i];
count++;
}
else if (strcmp(args[i], "|")) {
count = 0;
commandNum++;
}
//Looking at the next value in args
i++;
}
I'm running into problems because the only thing being put into arrayOfArgs is gibberish. I'm sure I've done something wrong with either the way the arrays are pointing, the way arrayOfArgs was created, or both.
OR is it even possible to go from a 1D to a 2D array like I'm trying?
I'm pretty sure there is a NULL there because earlier I call this loop and it works:
for(i = 0; args[i] != NULL; i++) {
printf("Argument %d: %s\n", i, args[i]);
}
Thanks!
First of all, how are you verifying that the contents of arrayOfArgs are gibberish? Are you printing out the contents with printf? Are you using a debugger?
Second of all, what is each element of arrayOfArgs supposed to store? Is it supposed to be a 3-element array of strings 9 characters or less? Is it supposed to be a 3x10 element array of pointers to char? Is it supposed to be a 3x10 element array of pointers to pointers to char?
In the line
arrayOfArgs[commandNum][count] = args[i];
the expression args[i] has type char *; that strongly implies that you intend for each element of arrayOfArgs to store a char *. In that case, change the declaration of arrayOfArgs to
char *arrayOfArgs[commands][10];
(I read this as each command can have up to 9 arguments).
IOW, it looks like you're trying to store something like
col 0 1 2 3 4 5 6 7 8 9
row
0 "cmd" "a1" "a2" NULL NULL NULL ...
1 "cmd" "a1" NULL
...
by storing pointers to each string in the 2D array.
If that's the case, then you need to change the declaration of arrayOfArgs as I said above. If that's not the case, then you need to give us an example of what arrayOfArgs is supposed to look like.
So I see some issues...
First I believe you mean to have char arrayOfArgs[commands][10]; as you want a 2D array of 10 character strings (i assume this is what you want)... otherwise it would be a 2D array of an array of string pointers (so like a 4D array of characters :P)
Next the code you have created will only copy into each of those command buffers the character | if the argument itself is |
If you are looking for the contents between the pipe symbols look into the function strchr and strncpy, with these functions I would loop through each arg and if and argument is the pipe symbol, |, find the next argument with the pipe symbol, loop through the arguments in between and then copy the characters in between into a dynamically allocated char array
Also, in your comments you say that the commands array will be dynamic... the way you have your program structured the data is statically allocated on the stack. To make this dynamic you will need to dynamically allocate onto the heap i.e. malloc/calloc
The problem is here:
char **arrayOfArgs[commands][10];
This declares an two dimension array of double char pointers, which is not what you want.
Try the following instead:
char *arrayOfArgs[commands][10];
EDIT: changed to char* because after examine the code I found the OP assigning a pointer to a character array to arrayOfArgs. Thanks to #wildplasser for notifying.
I figured it out. I decided to go a 1D array route rather than a 2D way. The code now takes args, which were split before as "ls" "-l" "|" "wc" and separates them based on if there is a pipe into a new array called "arrayOfCommands". The contents of arrayOfCommands are then, once this is through, "ls -l" and "wc". Here's the code:
int do_command(char **args,) {
const int commands = 2;
int i = 0;
int commandNum = 0;
int firstCommand = 1;
char *arrayOfCommands[commands];
//Go through args until we reach the end
while (args[i] != NULL){
//First case
if(firstCommand){
arrayOfCommands[commandNum] = args[i];
firstCommand = 0;
}
//Rest of the cases
else{
//if we find something that's not a pipe...
if(strcmp(args[i], "|")){
//Add a space to what was a previous part of the same command
arrayOfCommands[commandNum] = strcat(arrayOfCommands[commandNum]," ");
arrayOfCommands[commandNum] = strcat(arrayOfCommands[commandNum],args[i]);
}
//But if we do find a pipe...
else if (!strcmp(args[i], "|")) {
//We know it's time for a new command
commandNum++;
firstCommand = 1;
}
}
//Looking at the next value in args
i++;
}
for(i = 0; i < commands; i++)
printf("Command #[%d]: %s\n", i, arrayOfCommands[i]);
}