How to create variable size array that contains strings? - arrays

I have a problem trying to create a variable size array that contains strings. I have tried to create a multidimensional array, but it's too difficult. Example:
char *audio_types[8][40]; // 8 is number of string elements in the array by default; 40 is the maximum length of a string
audio_types = (char *) malloc(15); // increasing number of strings in the array
free(audio_types);
Moreover, I was trying to create variable size pointer array. Example:
char *audio_types[40]; // 40 is the maximum length of a string
*audio_types = (char *) malloc(8); // setting number of strings to 8
free(audio_types);
The problem is that I don't know how to create an array with variable number of string elements properly. Sorry, I am new in C programming. In the short, my code has to hold multiple string elements in one array. Example:
audio_types[0] // some string...
audio_types[1] // another string...
audio_types[2] // more another sting... etc.
Hope you understand what I am trying to ask. Thank you for your attention.

Maybe something like this. It will grow the size of the array when you add new types. It will also keep track of how many types you have in the array (it is needed if you resize the array dynamically and you need to know how many elements are in this array).
#define AUDIO_TYPE_LENGTH 40
typedef char audio_type[AUDIO_TYPE_LENGTH];
typedef struct
{
size_t size;
audio_type audio_types[];
}audioTypes_t;
audioTypes_t *AddType(audioTypes_t *types, const char *type)
{
size_t size = types ? types -> size : 0;
types = realloc(types, sizeof(*types) + (size + 1) * sizeof(types -> audio_types[0]));
if(types)
{
strncpy(types -> audio_types[size], type, sizeof(types -> audio_types[0] - 1));
types -> audio_types[size][sizeof(types -> audio_types[0] - 1)] = 0; //making strncpy safe
types -> size = size + 1;
}
return types;
}

You cannot change the size of an array in C. You could create a new array each time you want to resize and transfer the contents from the old array to the new one. Alternatively, you could use a list to store your strings.

When you define the array ( the char *audio_types[40]; line) in C it creates a contiguous block of memory to the 40 char pointers in the array. As memory is allocated when the array is defined you cannot make the array longer. To do that you would need a List data type, or you could create a new array when you want to add a new element which is the old one with the new element at the end.

char string[40] is an array of 40 characters that can hold 39 characters maximum (plus the string terminator) - the maximum size cannot be changed and 40 bytes of memory are used even if you store a short string containing 2 characters (plus the string terminator).
char *string is a pointer to some characters - the pointer can point anywhere: to a single character or any size array of characters. If it points to an array of characters (which you can make using malloc() then it can be thought of as a "string")
char *array[8] is an array of 8 "strings" (really it is 8 pointers to characters) The size of the array cannot be changed but the pointers can point anywhere: to a single character or any size array of characters. If the pointers point to an array of characters (which you can make using malloc() then they can be thought of as "strings")
char array[8][40] is a 2D array which you can think of as an array of 8 "strings" - where "strings" is defined as an array of 40 characters that can hold 39 characters maximum (plus the string terminator). You cannot change the size of either dimension.
char **array is a pointer to a char * - which could just be a single "string" or to an array of "strings". The sizes aren't fixed and can be dynamically created.
char *string1 = "asd"; means that string1 points to an array of 4 characters ("asd" plus the string terminator) that are in read-only memory - you cannot change the contents of the string but you can point string1 anywhere you want.
char string1[] = "asd"; means that string1 is an array of 4 characters that are filled up by the compiler with 4 characters ("asd" plus the string terminator) - you can change the contents of the array but you can't change the size.
So if you want a dynamically sized array of character strings you can do this:
#include <stdio.h> // printf
#include <stdlib.h> // malloc, realloc, free
#include <string.h> // strcpy, strdup
int main()
{
// make an array of 8 string pointers
int original_size = 8;
char **array = malloc(original_size * sizeof(char *));
// point each pointer to a string
// you don't have to do this all at once if you don't want to
for (int i=0; i<original_size; i++)
array[i] = malloc(40 * sizeof(char)); // max of 39 plus the terminator
// array[7] is already allocated so we can just use it as a string
strcpy(array[7],"asd"); // the last string that we malloced
// reallocate the array to be bigger
int new_size = 15;
array = realloc(array, new_size * sizeof(char *));
// array[14] is a pointer that doesn't point anywhere
// so we need to allocate space before filling it in
array[14] = strdup("qwe"); // points 3 characters plus the string terminator
printf("%s\n",array[7]);
printf("%s\n",array[14]);
// free the one we made with strdup
free(array[14]);
// free the 8 we malloced
for (int i=0; i<original_size; i++)
free(array[i]);
// now free the array we malloced and then realloced
free(array);
return 0;
}
Note: there is NO error checking in that program because I didn't want to mask the basic ideas - make sure you add error checking to any program you make
Try it at https://onlinegdb.com/XQeyOGd0C

Related

Double pointer array allocation C [duplicate]

This question already has answers here:
How do I dynamically allocate an array of strings in C?
(5 answers)
Closed 1 year ago.
I want to allocate an array for 6 words of a maximum of 30 charachters for example.
My teacher says I should allocate 6 "+1" to count for a NULL that I have to set my self
after inserting my words.
How exactly is a char **array is allocated and why is my teacher insisting ?
It sounds like your teacher wants you do use a null pointer at the end of the array, as a sentinel value. This is similar to null termination of individual strings and can sometimes be useful when the amount of strings is unknown.
When you allocate a single string you do char* str = malloc(length + 1); where the +1 is for the null terminator '\0. The extra +1 ensures that given length = strlen("hello");, we can safely do strcpy(str, "hello") to fill this string.
You can do something similar for an array of strings by
char** arr = malloc(sizeof(char*[size+1]));
If you then assign arr[size] = NULL; as sentinel value, it will be possible to iterate over this array in this way:
for(const char** ptr=arr; ptr!=NULL; ptr++)
{
printf("%s\n", *ptr); // do something with each string
}
But if you know the size, then the preferred method is a normal loop:
for(size_t i=0; i<size; i++)
{
printf("%s\n", arr[i]); // do something with each string
}
char **arr = calloc(7, sizeof(char*));
So let's break this down, calloc basically makes an array, first argument is the size of the array and the second is how much memory to allocate to every index of the array.

C reallocing a typedef?

I need a struct declaration that contains a single string which I can then make an array of(so basically an array of pointers to strings). I know how to make an array of structs which each contain a string:
typedef char line_t[MAX_INPUT + 1];
typedef struct {
line_t text;
} lines;
lines *arrayoflines;
arrayoflines = (char *)calloc(MAX_INPUT + 1, sizeof(char));
No issue here. However, what if the number of characters in the string that needs to be stored goes past the bounds of MAX_INPUT? I feel I'd need to realloc char line_t[MAX_INPUT + 1] and that is what I have absolutely no idea how to do.
Edit: Seems like some thought that the number of strings in the array of strings was the issue. I meant reallocating for the length of the string that can be stored in each element in the array of strings.
It is better to allocate memory for each line. I.e. instead of array of static arrays line_t[MAX_INPUT + 1] define array of char pointers: char ** arrayoflines.
You have a limit for the maximum line defined in your array. So, I assume any given line will never exceed that (you should check your input if this assumption is wrong). You can read a shorter line into the line_t (by terminating your string with a NULL), but you will not recover the space in memory. If you don't have many lines expected, your fixed buffer approach will work, i.e., you don't need to realloc.
However, if you need to be efficient with space, maybe because you will read millions of lines, you should allocate memory for each line. In other words, you might consider changing line_t to a char* instead of char[MAX_INPUT+1]. They are semantically equal for your programming purposes. But behind the scene, you are not setting a fixed size.
typedef char* line_t;
line_t *arrayoflines;
arrayoflines = calloc(1, sizeof(line_t));
arrayoflines[0] = calloc(MAX_INPUT + 1, sizeof(char));
//if you learn the size after reading into the buffer, and it's smaller,
// realloc the buffer - be sure to include space for NULL and be sure it
// is set to NULL
arrayoflines[0] = realloc(arrayoflines[0], (new_smaller_count+1) * sizeof(char))
arrayoflines[0][new_smaller_count] = NULL;
if you can not ensure that the all the inputs will be less or equal MAX_INPUT, you have to convert to dynamic allocation instead.
and by that you have to do this:
typedef struct {
char * text;
} lines;
lines *arrayoflines;
arrayoflines = calloc(MAX_LINES, sizeof(lines));
and for every (n) element allocate THE_DESIRED_INPUT_SIZE for that particular element;
arrayoflines[n].text=calloc(THE_DESIRED_INPUT_SIZE, sizeof(char));
the (n) is in range of [0,MAX_LINES-1]

how I can allocate an array of pointers and a 2D array by malloc in C?

I am coding a program which takes a text file as an input, makes the index of the words of it and prints the output(the index) in a file and in the screen.
the input file may be huge. but we KNOW that the maximum variety of the words used in the text file is 200. we don't know what's the maximum of lines and characters of each word. so I should reserve a large number for them. I took the maximum of line 1000 and the maximum characters of each word 100.
I am programming in Turbo C and (I am forced to use that). the compiler allocates just 64kb memory (with the size of the compiler included) and so I have to use MALLOC.
my program is supposed to work in this algorithm:
it reads the input file line by line with fgets. then in the current line, it reads word by word with strtok. so far I have the xth word in yth line. I want to put the words in an array of pointers. so I need a char * word[200]. and I want to show how many times, which word is repeated in which line. so I need a int index [200][1000]. if in yth line, the xth word is existed I would do index[x][y]++.
so now I need to allocate MALLOC memory to these char * word[200] and int index[200][1000] . Can anyone help? I tried all the answers to these question and none of them helped.
You don't quite have malloc right. Your malloc(100) is only allocating 100 bytes. You need
char * words[i] = malloc(sizeof(char *) * 100);
This allocates 800 bytes (100 elements of 8 bytes (size of a pointer) each).
Similarly, in the second malloc, you want two integers, you need
int index[i][j] = malloc(sizeof(int *) * 2);
You shouldn't cast to a pointer; it returns a void pointer, which is implicitly cast to whatever type of pointer you need just by virtue of the assignment.
http://www.cplusplus.com/reference/cstdlib/malloc/
FURTHERMORE:
Additionally, you're trying to stuff 2 bytes into an integer pointer or 4 bytes (100-96 = 4; the 96 is 8 * 12) into a character pointer. I have no idea in the world what that will do. The BEST you can hope for is that you'll just lose the memory somewhere and effectively have 12 character pointers and 2 memory leaks.
If I understand you
In the first loop, I want to define an array of 200 pointers that each pointer, points to an array of char blocks. I want each pointer, points to an array of maximum 100 bytes. Meaning 100 char blocks
char **words = NULL;
int i;
words = malloc(sizeof(char*) * 200);
for(i = 0; i < 200; i++) {
words[i] = malloc(100);
}
There's allocating 200 words with 100 bytes size here.
In the second loop, I want to define a 2D array of int blocks that each block is maximum 2 bytes. meaning 200 * 1000 int blocks.
int **index = NULL;
int i;
index = malloc(sizeof(int*) * 200)
for (i = 0; i < 200; i++) {
index[i] = malloc(sizeof(int) * 1000);
}
Here you allocate 200x1000 int array.
char * words = malloc(200*100);
int * index = malloc(200*1000*sizeof(int));
// word[i*200+j] : character j in word i
// index[i*200+j] : int at index i,j
alternatives:
// mallocing an array for storing a maximum of 200 malloced words
char ** words = malloc(200*sizeof(char*));
// adding a new word, at index i, which is pointed to by pszNewWord (null terminated)
words[i] = strdup(pszNewWord);

How to find the number of elements in char** array?

I have an string array in the form of char**
I am struggling to find the length of that array:
typedef struct _stringArray
{
int (*Length)(char**);
char** (*Push)(char**, char*);
char** (*Pop)(char**, char*);
}StringArray;
StringArray* StringArray_Constructor(void)
{
StringArray* stringArray = (StringArray *)malloc(sizeof(StringArray));
stringArray->Push = StringArray_Push;
stringArray->Pop = StringArray_Pop;
}
char** StringArray_Push(char** array, char* string)
{
int size = 0; //how to find how many elements in the array object???
array = realoc(array, (sizeof(char *) * (size + 1));
array[size] = string;
return array;
}
Any help would be greatly appreciated!
Thanks.
With C, you will have to keep track of this yourself.
There's no way you can infere the lenght of the array, the only way you could do it is doing it dynamically. You have an array of strings (char**), so you have the pointer to the first character of the first element of the array. We all know that, in C, all strings must ed with '\0', so you can "scan" for the strings of the array taking this pointer and saving it, then increment it until you get a '\0'. The next pointer is the first character of the next string and so on.
But this have a huge flaw: memory is not as linear as it appears. What I'm saying is that your first string can be entirely allocated at, e.g., address 0x0010101A, and the next at 0xF0FF0001, so or you hae a huge string #0x0010101A or there is a bunch of data beetween them and you do not know if they are part of the string or not.
And that's why you need to maintain a counter of how many strings you have. :)
PS: and as this number is always greater than zero, you should use unsigned int to type it.
You have a few options:
1) Pass a size parameter around which indicates the current size of your char **array.
2) Declare a structure which combines char **array with int array_size (really the same as #1).
3) If your array will always contain valid pointers (i.e. non-NULL) then create an extra element at the end which is always set to NULL. This acts as an array terminator, you can scan char **array looking for this terminating element:
int size;
for (size = 0; array[size] != NULL; size++);
// 'size' is number of valid entries in 'array'.

C -> sizeof string is always 8

#include "usefunc.h" //don't worry about this -> lib I wrote
int main()
{
int i;
string given[4000], longest = "a"; //declared new typdef. equivalent to 2D char array
given[0] = "a";
printf("Please enter words separated by RETs...\n");
for (i = 1; i < 4000 && !StringEqual(given[i-1], "end"); i++)
{
given[i] = GetLine();
/*
if (sizeof(given[i]) > sizeof(longest))
{
longest = given[i];
}
*/
printf("%lu\n", sizeof(given[i])); //this ALWAYS RETURNS EIGHT!!!
}
printf("%s", longest);
}
Why does it always return 8???
There is no string data type in C. Is this C++? Or is string a typedef?
Assuming string is a typedef for char *, what you probably want is strlen, not sizeof. The 8 that you are getting with sizeof is actually the size of the pointer (to the first character in the string).
It is treating it as a pointer, the sizeof a pointer is obviously 8bytes = 64 bits on your machine
You say "don't worry about this -> lib i wrote" but this is the critical piece of information, as it defines string. Presumably string is char* and the size of that on your machine is 8. Thus, sizeof(given[i]) is 8 because given [i] is a string. Perhaps you want strlen rather than sizeof.
This is common mistake between the array of characters itself, and the pointer to where that array starts.
For instance the C-style string literal:
char hello[14] = "Hello, World!";
Is 14 bytes (13 for the message, and 1 for the null terminating character).
You can use sizeof() to determine the size of a raw C-style string.
However, if we create a pointer to that string:
char* strptr = hello;
And attempt to find it's size with sizeof(), it will only always return the size of a data pointer on your system.
So, in other words, when you try to get the size of the string from a string library, you're truly only getting the size of the pointer to the start of that string. What you need to use is the strlen() function, which returns the size of the string in characters:
sizeof(strptr); //usually 4 or 8 bytes
strlen(strptr); //going to be 14 bytes
Hope this clears things up!

Resources