how do i use malloc when I am in infinite while loop - c

I have a program that repeatedly asks user input a line and stores them in an array.
I know how to use dynamic memory allocation to make array if I can get a number of items to store at runtime.
for example
char **array = (char**)malloc(numberOfItems * sizeof(char*));
but in my case, I do not know numberOfItems at runtime because I am getting input within a while loop which can be terminated by ctrl+D.
while(!feof(stdin)
{
array[i] = (char*)malloc(167 * sizeof(char));
}
Any help, please.

You can use realloc() to grow the size of memory obtained through malloc(), calloc(), or realloc().
int capacity = 10;
char **array = malloc(capacity* sizeof(char*));
int i = 0;
char line[256];
while(fgets(line, sizeof(line), stdin)) {
// Resize array when at capacity
if (i == capacity) {
capacity *= 2;
array = realloc(array, capacity * sizeof(char*));
}
array[i] = malloc(167 * sizeof(char));
i++;
}
A few related notes:
Doubling the size of the container each time it grows is more efficient than growing by a constant amount. Read more here.
Don't cast the result of malloc()
Don't use feof() in a loop
Hopefully that is enough to get you started!

Related

Dynamically Allocate Memory for String Array in C

I'm trying to store a list of every mount point on a Linux system in a string array with C. I'm focused on this piece of code.
int i = 0;
char **mountslist = malloc(1024 * sizeof(char *));
/*
* Make sure that the number entries in the array are less than the allocated
* 1024 in the absurd case that the system has that many mount points.
*/
while (i < 1024 && (ent = getmntent(mounts))) {
/*
* The output of getmntent(mounts) goes down to
* the next mount point every time it is called.
*/
mountslist[i] = strdup(ent->mnt_dir);
i++;
}
I was wondering how I could dynamically allocate the number of entries in the mountslist array (currently statically set at 1024) to avoid that limit and wasting memory. If I had the final value of i when declaring mountslist I could use char *mountslist[i]; or char **mountslist = malloc(i * sizeof(char *));
You can use realloc to change the size of an allocated memory block:
int i = 0;
int len = 10;
char **mountslist = malloc(len * sizeof(char *));
while ((ent = getmntent(mounts)) != NULL) {
if (i >= len) {
len *= 2;
char **tmp = realloc(mountslist, len * sizeof(char *));
if (tmp) {
mountslist = tmp;
}
}
mountslist[i] = strdup(ent->mnt_dir);
i++;
}
As shown above, a good rule is to double the amount of space you allocate when you run out of space. That prevents excessive calls to realloc which may move the allocated memory each time.

How to add a dynamically allocated string to array of strings in C?

I have to write a function that adds the given string to array of strings.
char **add_string(char **array, const char *string)
{
array = realloc(array, (sizeof(string)) * sizeof(char *));
int i = 0;
while (array[i] != NULL){
i++;
}
array[i] = malloc((strlen(string) + 1));
strcpy(array[i], string);
array[i + 1] = NULL;
return array;
}
At the moment I get memory leaks according to Valgrid. I didn't use malloc correctly, but I can't figure out how to fix it. I would really appreciate your help.
The realloc allocates a new size given its second argument but you are not increasing the size, so basically every time you call your function it allocates the same size not increasing the area allocated.
you would need to pass the current number of strings in the array to add_string and then increment it in the add_string
char** add_string(char** array, int* size, const char* string)
{
char* newArray = realloc(array, (*size + 1) *sizeof(char*) );
newArray[*size] = malloc(strlen(string)+1);
strcpy(newArray[*size], string);
*size += 1;
...
}
You should also check if realloc succeeds or not by checking the return value.
Normally the above method is not a very effective way to handle increasing sizes since you are calling realloc every time and that is time consuming. Instead you should allocate in chunks then keep track of how much of the chunk you have used up, when the chunk is used up realloc a new one.
Your re-allocation of array is broken, it needs to search to figure out how long the array is, assuming it's always "tightly" allocated (with the last allocated element being the only one that is NULL).
char **add_string(char **array, const char *string){
int i = 0;
while (array[i] != NULL){
i++;//First, count the elements and find NULL element
}
array[i] = malloc(strlen(string) + 1);//or strdup(string);
strcpy(array[i], string);
char **temp;
temp = realloc(array, (i+1+1) * sizeof(char *));
if(temp == NULL){
perror("realloc at add_string");
} else {
array = temp;
array[i + 1] = NULL;
}
return array;
}

is this a nice way to allocate memory for an array of arrays? (C)

Okay, imagine I have a char**, would this be the correct way to allocate memory?
I mean: allocate memory for the char** itself and then for each char*...
char** fraseUsuario = NULL;
int length = 100, i = 0;
fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure
for (i = 0; i < 3; i++) {
fraseUsuario[i] = (char *) malloc(length * sizeof (char));
if (fraseUsuario[i] == NULL) {
printf("error\n");
return -1;
}
gets(fraseUsuario[i]);
}
for (i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]);
}
And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?
What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.
char **fraseUsuario = NULL;
I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.
char **fraseUsuario = NULL;
int max_string_len = 100 + 1; // maximum string length. +1 for null byte
int num_string = 3; // number of strings to read
int i, j;
fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) { // check for NULL
// handle the case
printf("not enough memory\n");
return -1;
}
for(i = 0; i < num_string; i++) {
fraseUsuario[i] = malloc(max_string_len * sizeof(char));
if(fraseUsuario[i] == NULL) { // check for NULL
printf("not enough memory\n");
for(j = 0; j < i; j++)
free(fraseUsuario[j]); // free memory before returning
free(fraseUsuario); // free memory before returning
return -1;
}
if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
// reading string failed
*fraserUsuario[i] = '\0'; // empty string
}
}
for(i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]); // free memory allocated for strings
}
free(fraseUsuario); // free memory allocated for pointers to strings
fraseUsuario = NULL;
When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.
You only allocate memory for one char* but use three.
To fix this do:
#define STR_MAXIMUM (3)
...
size_t length = 100, i = 0; /* No need to use a signed type.
size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario));
for (i = 0; i < STR_MAXIMUM; ++i)
{
fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));
...
Also add error checking to system calls.
Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.
fgets(fraseUsuario[i], length, stdin);

Resizing an array in C

Say I assigned an array like so:
char* array[]={"This"};
And then later I wanted to assign array[ ] a new value so that it stores "This" and "That," is there a way that I could change the size of array so that it could hold a new number of values?
No, you can't change the size of an array. You could use a dynamically allocated list of char* instead and realloc() as required:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main()
{
char** array = malloc(1 * sizeof(*array));
if (array)
{
array[0] = "This";
printf("%s\n------\n", array[0]);
char** tmp = realloc(array, 2 * sizeof(*array));
if (tmp)
{
array = tmp;
array[1] = "That";
printf("%s\n", array[0]);
printf("%s\n", array[1]);
}
free(array);
}
return 0;
}
See online demo: https://ideone.com/ng00k.
There is no way to resize an array. You can simply create a new array of size 2, then copy all the data from the previous one to the new one. realloc does it for you with dynamic memory. The better way is to use data structures such as LinkedLists or Vectors which you can find more about online.
You cannot resize array objects.
You would have to dynamically allocate the memory for array and extend it using realloc. Example:
size_t current_size = 0;
char **array = malloc((current_size + 1) * sizeof *array);
if (array)
{
array[current_size++] = "This";
}
...
/**
* If realloc cannot extend the buffer, it will return NULL and leave
* the original buffer intact; however, if we assign NULL back to array,
* we lose our handle to the original buffer, causing a memory leak, so
* we assign the result to a temporary variable.
*/
char **tmp = realloc(array, (current_size + 1) * sizeof *array)
if (tmp)
{
array = tmp;
array[current_size++] = "That";
}
else
{
// realloc failed to extend the buffer; original buffer
// is left intact.
}
Caveats:
realloc is a relatively expensive call, so you (generally) don't want to extend your buffer one element at a time like I did here. A more common strategy is to pick an initial starting size that covers most cases, and if you need to extend the buffer, double its size.
You could abstract the resize operation into a separate function, like so:
int addItem(char ***arr, char *newElement, size_t *count, size_t *bufSize)
{
if (*count == *bufSize)
{
// we've run out of room; extend the buffer
char **tmp = realloc(**arr, 2 * *bufSize * sizeof **arr);
if (tmp)
{
*arr = tmp;
*bufSize *= 2;
}
else
{
// could not extend the buffer; return failure code
return 0;
}
}
(*arr)[(*count)++] = newElement;
}
and call it as
#define N ... // initial array size
char **array = malloc(N * sizeof *array);
size_t bufSize = N;
size_t count = 0;
...
if (addItem(&array, "This", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
if (addItem(&array, "That", &count, &bufSize))
printf("# elements = %zu, buffer size = %zu\n", count, bufSize);
This is all untested and off the top of my head; no warranties express or implied. But it should be enough to point you in the right direction.
This is not possible. You can allocate an array of char*, though:
char **array = calloc(2, sizeof(char *));
array[0] = "This";
array[1] = "That";

How can allocate multi dimensional array at run time?

at design time I could have declare a variable like this:
char szDesignTimeArray[120][128];
The above declaration is 120 arrays of size 128. At run time I need to allocate the following:
char szRunTime[?][128];
I know the size of the arrays but I do not how many arrays I need to allocate. How can I declare this and allocate them when I know the number?
Thnaks all
I assume at run-time you know the Row_Size as well.
You can dynamically allocate a multidimensional array at run time, as follows:
#include <stdlib.h>
int **array;
array = malloc(nrows * sizeof(int *));
if(array == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
for(i = 0; i < nrows; i++)
{
array[i] = malloc(ncolumns * sizeof(int));
if(array[i] == NULL)
{
fprintf(stderr, "out of memory\n");
exit or return
}
}
Reference:
http://www.eskimo.com/~scs/cclass/int/sx9b.html
With the length of the rows statically know, you could also allocate
char (*szRunTime)[128];
// obtain row count
szRunTime = malloc(rowCount * sizeof *szRunTime);
memory to a pointer to char[128]. That way, you get a contiguous block of memory, which may give better locality, and you need only free one pointer.
If the number of rows is not too large, using a variable length array,
rowCount = whatever;
char szRunTime[rowCount][128];
may however be the best option if C99 or later is supported.
use this ,, where Variable is the how many array you want :
char **szRunTime = malloc(sizeof(char *)*Variable);
int i;
for(i=0 ; i<Variable ; i++)
szRunTime[i] = malloc(sizeof(char)*128);

Resources