I tried to increase a double pointer buffer in another method/function. However, the size of the allocated buffer does not changes. Here is the code I tried.
#include <stdio.h>
#include <stdlib.h>
void change_buffer_size(char ** buffer)
{
*buffer = realloc(*buffer, sizeof(char) * 2);
}
int main()
{
char **buffer = malloc(sizeof(char) * 1);
*buffer[0] = 'H';
change_buffer_size(buffer);
*buffer[1] = 'i';
printf("%s\n", *buffer);
return 0;
}
I get the Segmentation fault (core dumped) error.
char **buffer = malloc(sizeof(char) * 1);
This is wrong. You now have a char**, so the thing that it points to is a char*, but there's only enough room in it for a char. You also only allocated one layer of the double pointer.
*buffer[0] = 'H';
This line causes the segfault because of the above problems. It's trying to write to memory in an undefined location.
The best way to fix this is to just allocate the first layer normally, use & where necessary, and only use malloc for the second layer.
Also, %s doesn't stop writing until it sees a null byte, so you need to allocate and write one of them. Here's how you fix it all:
#include <stdio.h>
#include <stdlib.h>
void change_buffer_size(char ** buffer)
{
*buffer = realloc(*buffer, sizeof(char) * 3);
}
int main()
{
char *buffer = malloc(sizeof(char) * 1);
buffer[0] = 'H';
change_buffer_size(&buffer);
buffer[1] = 'i';
buffer[2] = '\0';
printf("%s\n", buffer);
return 0;
}
You already have a good answer by #JosephSible but there is one further point that needs making about the use of realloc. I've alluded to this in the comment under the original question. When using realloc, you must always realloc using a temporary pointer to capture the return of realloc.
Why? When (not if) realloc fails, it returns NULL. If you assign the return directly to the pointer you are attempting to reallocate for, you overwrite the pointer to your existing block of memory with NULL losing your reference to the original block creating a memory leak. For example, you do not want to:
*buffer = realloc (*buffer, 2); /* sizeof(char) is always 1 */
Instead, use a temporary pointer and validate the reallocation succeeds before assigning the reallocated block to your original pointer, e.g.
void * tmp = realloc (*buffer, 2);
if (!tmp) { /* validate EVERY allocation & reallocation */
perror ("realloc-*buffer");
exit (EXIT_FAILURE); /* or handle as desired, e.g return NULL, etc.. */
}
*buffer = tmp; /* now assign the reallocated block to your pointer */
A couple of comments on your original post. Recall in C a string must end with a nul-terminating character. You cannot simply assign buffer[0] = 'H'; and treat buffer as a string. The nul-termianting character ('\0', or simply 0) must follow, so you would need buffer[1] = 0; before calling printf("%s\n", *buffer);
Avoid using Magic-Numbers in your code. Your change_buffer_size() function hardcodes the reallocation to size using the magic-number 2. (not very useful). Instead, at least pass the desired size as a parameter so your function is reusable, e.g.
char *change_buffer_size (char **buffer, size_t nchar)
{
void *tmp = realloc (*buffer, nchar * sizeof **buffer);
if (!tmp) { /* validate EVERY allocation/reallocation */
perror ("change_buffer_size()-realloc");
return NULL;
}
return *buffer = tmp; /* assign new block to *buffer, return */
}
(note: changing the return type to char* allows you to indicate success/failure of the function through the return as well as having direct access to the reallocated block of memory on success)
Now is you want to reallocate your buffer to 2-characters, just pass 2 as nchar, etc.. That combined with a short example that reallocates and adds a character to your buffer at a time (while ensuring it is always nul-terminated) could be something like the following:
#include <stdio.h>
#include <stdlib.h>
char *change_buffer_size (char **buffer, size_t nchar)
{
void *tmp = realloc (*buffer, nchar * sizeof **buffer);
if (!tmp) { /* validate EVERY allocation/reallocation */
perror ("change_buffer_size()-realloc");
return NULL;
}
return *buffer = tmp; /* assign new block to *buffer, return */
}
int main (void) {
size_t nchar = 1; /* character counter */
char *str = "hello world!", *buffer = NULL;
for (int i = 0; str[i]; i++) {
if (!change_buffer_size(&buffer, nchar + 1)) /* alloc nchar + 1 */
return 1;
buffer[nchar-1] = str[i]; /* copy char from str to buffer */
buffer[nchar++] = 0; /* nul-terminate buffer */
printf ("buffer: '%s'\n", buffer); /* print current buffer contents */
}
free (buffer); /* don't forget to free what you allocate */
}
(note: don't forget to free() the memory you allocate. Yes, here it will be freed on program exit, but build good habits early -- you will not always be working in main())
Example Use/Output
$ ./bin/realloccharbuf
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/realloccharbuf
==19740== Memcheck, a memory error detector
==19740== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19740== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==19740== Command: ./bin/realloccharbuf
==19740==
buffer: 'h'
buffer: 'he'
buffer: 'hel'
buffer: 'hell'
buffer: 'hello'
buffer: 'hello '
buffer: 'hello w'
buffer: 'hello wo'
buffer: 'hello wor'
buffer: 'hello worl'
buffer: 'hello world'
buffer: 'hello world!'
==19740==
==19740== HEAP SUMMARY:
==19740== in use at exit: 0 bytes in 0 blocks
==19740== total heap usage: 13 allocs, 13 frees, 1,114 bytes allocated
==19740==
==19740== All heap blocks were freed -- no leaks are possible
==19740==
==19740== For counts of detected and suppressed errors, rerun with: -v
==19740== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have questions.
Related
I'm trying to malloc array of strings in a struct and it doesn't work well.
I also want to check the size of the arrays but I don't get the right values
what is wrong with my code?
by the way, I know I should free the memory allocation..
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct{
char** string;
} Strt;
int main(int agrc, char *argv[]) {
int i;
int size1 = 0, size2 = 0;
char** arrr;
Strt* arr = malloc(sizeof(Strt));
printf("number of arrays: ");
scanf("%d", &size1);
printf("size of each array: ");
scanf("%d", &size2);
arr->string = (char**)malloc(size1 * sizeof(char));
printf("size of string: %d\n", sizeof(arr->string));
for(i = 0; i < size1; i++){
arr->string[i] = (char*)malloc(size2 * sizeof(char));
}
return 0;
}
It looks like you are wanting to allocate for an unknown number of strings. You are thinking correctly that you will want to use a pointer-to-pointer-to char (e.g. char **arr;), but the "train fell off the tracks" so to speak when you went to implement the logic.
Let's look at what you need to do to read and store an unknown number of strings (or any object for that matter). It is a two-step process where you:
allocate storage for pointers, one for each object you wish to store, and
allocate a block of storage for each object, copying the object to the newly allocated block and assigning the beginning address of that block to one of your pointers.
To grow the number of objects stored, you realloc() more pointers and keep going until you run out of objects to store.
When you realloc(), you always use a temporary pointer. Why? Because when (not if) realloc() fails, it returns NULL and if you are simply calling realloc() with the pointer itself, you overwrite the address to the current block of memory with NULL losing the original pointer that can now no longer be freed.
So instead of:
arr = realloc (arr, /* how big */);
You do:
/* always realloc using temp pointer to avoid mem-leak on realloc failure. */
void *tmp = realloc (arr, (nstr + 1) * sizeof *arr); /* realloc pointers */
if (!tmp) { /* VALIDATE EVERY ALLOCATION */
perror ("realloc-tmp");
break;
}
arr = tmp; /* assign reallocated block of pointers to arr */
Now if I understand correctly (though I am not 100% clear on) your need to read and store an unknown number of strings, you do not need a struct. Look at Strt -- it is a single-member struct. The struct serves no purpose there. You simply want a pointer to a block of pointers which you can grow. So char **arr; is all that is needed. Other than that you need a counter to keep track of now many strings are stored, and for the actual read of the string, simply use a fixed size buffer with fgets() or use POSIX getline(). So your setup for beginning to read strings could be:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC], /* buffer to hold each line read */
**arr = NULL; /* pointer-to-pointer-to char */
size_t nstr = 0; /* counter for number of strings stored */
...
Above you will read all input into buf, then you can trim the '\n' included by fgets(), obtaining the length of the input so you can then allocate length + 1 characters of storage for the string (+1 for the nul-terminating character) assigning the beginning address of the new block to the next available pointer. You then copy from buf to your newly allocated block and increment your counter.
(A simple way to trim the '\n' and obtain the length of the input is with strcspn())
Putting those pieces together, your read, trim, reallocation, allocation of the new block and copy to it could be done with:
for (;;) { /* loop continually reading input */
size_t len; /* var to hold length of string after \n removal */
fputs ("enter string (EOF to quit): ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin)) { /* read line (or EOF) */
puts ("(all done)\n");
break;
}
buf[(len = strcspn (buf, "\r\n"))] = 0; /* trim \n, save len */
/* always realloc using temp pointer to avoid mem-leak on realloc failure. */
void *tmp = realloc (arr, (nstr + 1) * sizeof *arr); /* realloc pointers */
if (!tmp) { /* VALIDATE EVERY ALLOCATION */
perror ("realloc-tmp");
break;
}
arr = tmp; /* assign reallocated block of pointers to arr */
if (!(arr[nstr] = malloc (len + 1))) { /* allocate/validate block for string */
perror ("malloc-arr[nstr]");
break;
}
memcpy (arr[nstr++], buf, len + 1); /* copy string to allocated block */
}
(note: the manual EOF is generated by the user pressing Ctrl + d -- or Ctrl + z on windows)
All that remains is outputting the stored string (or using them however you need) and then freeing the allocated memory:
for (size_t i = 0; i < nstr; i++) { /* loop outputting strings */
puts (arr[i]);
free (arr[i]); /* free string */
}
free (arr); /* free pointers */
}
If you put the whole program together you would have:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main (void) {
char buf[MAXC], /* buffer to hold each line read */
**arr = NULL; /* pointer-to-pointer-to char */
size_t nstr = 0; /* counter for number of strings stored */
for (;;) { /* loop continually reading input */
size_t len; /* var to hold length of string after \n removal */
fputs ("enter string (EOF to quit): ", stdout); /* prompt */
if (!fgets (buf, MAXC, stdin)) { /* read line (or EOF) */
puts ("(all done)\n");
break;
}
buf[(len = strcspn (buf, "\r\n"))] = 0; /* trim \n, save len */
/* always realloc using temp pointer to avoid mem-leak on realloc failure. */
void *tmp = realloc (arr, (nstr + 1) * sizeof *arr); /* realloc pointers */
if (!tmp) { /* VALIDATE EVERY ALLOCATION */
perror ("realloc-tmp");
break;
}
arr = tmp; /* assign reallocated block of pointers to arr */
if (!(arr[nstr] = malloc (len + 1))) { /* allocate/validate block for string */
perror ("malloc-arr[nstr]");
break;
}
memcpy (arr[nstr++], buf, len + 1); /* copy string to allocated block */
}
for (size_t i = 0; i < nstr; i++) { /* loop outputting strings */
puts (arr[i]);
free (arr[i]); /* free string */
}
free (arr); /* free pointers */
}
(note: while you would normally what to allocate blocks of pointers keeping track of the number available and number used and only reallocating when used == available to minimize the number of reallocations needed -- when taking user input, there is no efficiency to be gained due to the delay caused by the user in pecking out the input. But know you can optimize by minimizing the number of reallocations needed)
Example Use/Output
$ ./bin/allocate_p2p
enter string (EOF to quit): My dog
enter string (EOF to quit): has fleas...
enter string (EOF to quit): My cat
enter string (EOF to quit): has none...
enter string (EOF to quit): Lucky cat!
enter string (EOF to quit): (all done)
My dog
has fleas...
My cat
has none...
Lucky cat!
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/allocate_p2p
==16556== Memcheck, a memory error detector
==16556== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==16556== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==16556== Command: ./bin/allocate_p2p
==16556==
enter string (EOF to quit): My dog
enter string (EOF to quit): has fleas...
enter string (EOF to quit): My cat
enter string (EOF to quit): has none...
enter string (EOF to quit): Lucky cat!
enter string (EOF to quit): (all done)
My dog
has fleas...
My cat
has none...
Lucky cat!
==16556==
==16556== HEAP SUMMARY:
==16556== in use at exit: 0 bytes in 0 blocks
==16556== total heap usage: 12 allocs, 12 frees, 2,218 bytes allocated
==16556==
==16556== All heap blocks were freed -- no leaks are possible
==16556==
==16556== For counts of detected and suppressed errors, rerun with: -v
==16556== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if I read between the lines correctly as to what you needed, or if I missed. I'm happy to help further if what you need is slightly different. However looking at what you were trying to do, this seemed like what you were aiming at. Let me know if you have further questions.
I have the following two functions which takes an arrays of strings and makes them lowercase (in-place) --
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
void to_lower(char ** strings) {
char * original_string;
char * lower_string;
for (int i=0; (original_string=strings[i]) != NULL; i++) {
lower_string = malloc(strlen(original_string + 1) * sizeof(char));
for (int j=0; j<=strlen(original_string); j++) {
lower_string[j] = tolower(original_string[j]);
}
strings[i]=lower_string;
}
}
int main(void) {
char * strings[] = {"Hello", "Zerotom", "new", NULL };
to_lower(strings);
to_lower(strings); // this and successive calls won't change
to_lower(strings); // anything but are here to try and understand malloc
to_lower(strings);
to_lower(strings);
return 0;
}
At the beginning of the main function before to_lower is called, how much memory is consumed? My guess was 16 bytes from the array of chars (15 chars + 1 null byte at end).
After to_lower has run 5 times and before the function is returned, how much memory has been consumed? Where should I be "free"-ing the strings that are being passed into the function (as my thought was calling malloc every time a string is copied/lower-cased it creates that much additional memory but never frees anything.
Does the to_lower function look ok, or how can it be modified so that it doesn't leak memory if it currently is?
You are wrapping yourself around the axle (confusing yourself) by combining the allocation and conversion to lower into a single void to_lower(char ** strings) function. Just as you have found, if you want to call the function twice on the same object, you have to free the memory you allocated to hold the lowercase strings in between calls -- but then you have lost the pointers to your original strings..
While there is nothing wrong with combining multiple operations in a function, you do have to step back and make sure what you are doing makes sense and won't cause more problems than it solves.
Your allocation and copying of strings is required before you modify the strings contained in strings because you initialize strings as an array of pointers to string-literals. String-literal are immutable (on all but a very few systems) created in read-only memory (generally the .rodata section of the executable). Attempting to modify a string-literal will just about guarantee a SegFault (on all but the quirky few systems)
Further, how are you going to get the original strings back if you have already overwritten the pointer addresses to the originals with pointers to allocated memory holding the lower-case results? (not to mention the tracking headache you create by replacing pointers to literals with pointers to allocated memory as far as when it is okay to free those pointers).
Here it is far better to leave you original strings untouched and simply allocate a copy of the original (by allocating pointers, including one for the sentinel value, and allocating storage for each of the original strings and then copy the original strings before converting to lowercase. This solves your problem with memory leaks as well as the problem with losing your original pointers to the string literals. You can free the lowercase strings as needed and you can always make another copy of the originals to send to your conversion function again.
So how would you go about implementing this? The easiest way is just to declare a pointer to pointer to char (e.g. a double-pointer) to which you can assign a block of memory for any number of pointers you like. In this case just allocate the same number of pointers as you have in the strings array, e.g.:
char *strings[] = {"Hello", "Zerotom", "new", NULL };
size_t nelem = *(&strings + 1) - strings; /* number of pointers */
/* declare & allocate nelem pointers */
char **modstrings = malloc (nelem * sizeof *modstrings);
if (!modstrings) { /* validate EVERY allocation */
perror ("malloc-modstrings");
}
(note: you can also use sizeof strings / sizeof *strings to obtain the number of elements)
Now that you have modstrings assigned a block of memory holding the same number of pointers as you have in strings, you can simply allocate blocks of memory sufficient to hold each of the string literals and assign the starting address for each block to successive pointers in modstrings setting the last pointer NULL as your sentinel, e.g.
void copy_strings (char **dest, char * const *src)
{
while (*src) { /* loop over each string */
size_t len = strlen (*src); /* get length */
if (!(*dest = malloc (len + 1))) { /* allocate/validate */
perror ("malloc-dest"); /* handle error */
exit (EXIT_FAILURE);
}
memcpy (*dest++, *src++, len + 1); /* copy *src to *dest (advance) */
}
*dest = NULL; /* set sentinel NULL */
}
(note: by passing the src parameter as char * const *src instead of just char **src, you can indicate to the compiler that src will not be changed allowing further optimizations by the compiler. restrict would be similar, but that discussion is left to another day)
Your to_lower function then reduces to:
void to_lower (char **strings) {
while (*strings) /* loop over each string */
for (char *p = *strings++; *p; p++) /* loop over each char */
*p = tolower (*p); /* convert to lower */
}
As a convenience, since you know you will want to copy strings to modstrings before each call to to_lower, you can combine both functions into a single wrapper (that does make sense to combine), e.g.
void copy_to_lower (char **dest, char * const *src)
{
copy_strings (dest, src); /* just combine functions above into single */
to_lower (dest);
}
(you could even add the print_array and free_strings above as well if you always want to do those operations in a single call as well -- more later)
In between each copy_to_lower and print_array of modstrings you will need to free the storage assigned to each pointer so you do not leak memory when you call copy_to_lower again. A simple free_strings function could be:
void free_strings (char **strings)
{
while (*strings) { /* loop over each string */
free (*strings); /* free it */
*strings++ = NULL; /* set pointer NULL (advance to next) */
}
}
You can now allocate, copy, convert to lower, print, and free as many times as you like in main(). you would simply make repeated calls to:
copy_to_lower (modstrings, strings); /* copy_to_lower to modstrings */
print_array (modstrings); /* print modstrings */
free_strings (modstrings); /* free strings (not pointers) */
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
...
Now recall, you are freeing the storage for each string when you call free_strings, but you are leaving the block of memory containing the pointers assigned to modstrings. So to complete your free of all memory you have allocated, don't forget to free the pointers, e.g.
free (modstrings); /* now free pointers */
Putting it altogether into an example you could do the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void print_array (char **strings)
{
while (*strings)
printf ("%s, ", *strings++);
putchar ('\n');
}
void free_strings (char **strings)
{
while (*strings) { /* loop over each string */
free (*strings); /* free it */
*strings++ = NULL; /* set pointer NULL (advance to next) */
}
}
void copy_strings (char **dest, char * const *src)
{
while (*src) { /* loop over each string */
size_t len = strlen (*src); /* get length */
if (!(*dest = malloc (len + 1))) { /* allocate/validate */
perror ("malloc-dest"); /* handle error */
exit (EXIT_FAILURE);
}
memcpy (*dest++, *src++, len + 1); /* copy *src to *dest (advance) */
}
*dest = NULL; /* set sentinel NULL */
}
void to_lower (char **strings) {
while (*strings) /* loop over each string */
for (char *p = *strings++; *p; p++) /* loop over each char */
*p = tolower (*p); /* convert to lower */
}
void copy_to_lower (char **dest, char * const *src)
{
copy_strings (dest, src); /* just combine functions above into single */
to_lower (dest);
}
int main(void) {
char *strings[] = {"Hello", "Zerotom", "new", NULL };
size_t nelem = *(&strings + 1) - strings; /* number of pointers */
/* declare & allocate nelem pointers */
char **modstrings = malloc (nelem * sizeof *modstrings);
if (!modstrings) { /* validate EVERY allocation */
perror ("malloc-modstrings");
}
copy_to_lower (modstrings, strings); /* copy_to_lower to modstrings */
print_array (modstrings); /* print modstrings */
free_strings (modstrings); /* free strings (not pointers) */
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
copy_to_lower (modstrings, strings); /* ditto */
print_array (modstrings);
free_strings (modstrings);
free (modstrings); /* now free pointers */
}
Example Use/Output
$ ./bin/tolower_strings
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/tolower_strings
==5182== Memcheck, a memory error detector
==5182== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5182== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==5182== Command: ./bin/tolower_strings
==5182==
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
hello, zerotom, new,
==5182==
==5182== HEAP SUMMARY:
==5182== in use at exit: 0 bytes in 0 blocks
==5182== total heap usage: 13 allocs, 13 frees, 104 bytes allocated
==5182==
==5182== All heap blocks were freed -- no leaks are possible
==5182==
==5182== For counts of detected and suppressed errors, rerun with: -v
==5182== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Now this is a long post, but you have made progress on learning dynamic allocation. It will take you a while to digest it all, but if you have further questions just let me know.
Does the to_lower function look ok, or how can it be modified so that
it doesn't leak memory if it currently is?
As pointed out by #chux in comments, you need to add 1 to the len of orginal_string, not to the pointer itself.
Regarding your question, yes, it leaks, each call to malloc wants a call to free. The problem here is: you are not allowed to call free on the initial values since they are filled with string-literals.
A posible solution is:
extern char *strdup(const char *);
static char *dup(const char *str)
{
char *res = strdup(str);
if (res == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
return res;
}
int main(void)
{
char *strings[] = {
dup("Hello"),
dup("Zerotom"),
dup("new"),
NULL
};
...
Now you can call to_lower and you don't need to malloc inside the function, just call free for each element at the very end when the array is no longer needed.
Notice that strdup is not part of the standard (but is avaliable on many implementations)
Every time to_lower() is called, you are replacing all string literals with dynamic memory pointers.
If you are calling to_lower() again without freeing existing memory, there is a memory leak.
lower_string = malloc(strlen(original_string + 1) * sizeof(char));
for (int j=0; j<=strlen(original_string); j++) {
lower_string[j] = tolower(original_string[j]);
}
strings[i]=lower_string;
So that when strings[] array is no longer needed, you should free all its memory.
E.g.
for (int i=0; strings[i] != NULL; i++) {
free(strings[i]);
strings[i] = NULL;
}
As an alternative to {"Hello", "Zerotom", "new", NULL }; and malloc() and friends, form the array of pointers char * strings[] to be initialized with pointers to modifiable data.
Since C99, use compound literals.
void inplace_strtolower(char * s) {
while (*s) {
*s = (char) tolower((unsigned char ) *s);
s++;
}
}
// "Non-const string literal"
// Compound literal from string literal"
#define NCSL(sl) ((char[sizeof(sl)]) { sl })
int main(void) {
char * strings[] = {NCSL("Hello"), NCSL("Zerotom"), NCSL("new"), NULL};
inplace_strtolower(strings[0]);
inplace_strtolower(strings[1]);
inplace_strtolower(strings[2]);
puts(strings[0]);
puts(strings[1]);
puts(strings[2]);
return 0;
}
Output
hello
zerotom
new
Is there a function which I can use that which will allow me to replace a specific texts.
For example:
char *test = "^Hello world^"; would be replaced with char *test = "<s>Hello world</s>";
Another example: char *test2 = "This is ~my house~ bud" would be replaced with char *test2 = "This is <b>my house</b> bud"
Before you can begin to replace substrings within a string, you have to understand what you are dealing with. In your example you want to know whether you can replace characters within a string, and you give as an example:
char *test = "^Hello world^";
By being declared and initialized as shown above test, is a string-literal created in read-only memory (on virtually all systems) and any attempt to modify characters stored in read-only memory invokes Undefined Behavior (and most likely a Segmentation Fault)
As noted in the comments, test could be declared and initialized as a character array, e.g. char test[] = "^Hello world^"; and insure that test is modifiable, but that does not address the problem where your replacement strings are longer than the substrings being replaced.
To handle the additional characters, you have two options (1) you can declare test[] to be sufficiently large to accommodate the substitutions, or (2) you can dynamically allocate storage for the replacement string, and realloc additional memory if you reach your original allocation limit.
For instance if you limit the code associated with test to a single function, you could declare test with a sufficient number of characters to handle the replacements, e.g.
#define MAXC 1024 /* define a constant for the maximum number of characters */
...
test[MAXC] = "^Hello world^";
You would then simply need to keep track of the original string length plus the number of character added with each replacement and insure that the total never exceeds MAXC-1 (reserving space for the nul-terminating character).
However, if you decided to move the replacement code to a separate function -- you now have the problem that you cannot return a pointer to a locally declared array (because the locally declared array is declared within the function stack space -- which is destroyed (released for reuse) when the function returns) A locally declared array has automatic storage duration. See: C11 Standard - 6.2.4 Storage durations of objects
To avoid the problem of a locally declared array not surviving the function return, you can simply dynamically allocate storage for your new string which results in the new string having allocated storage duration which is good for the life of the program, or until the memory is freed by calling free(). This allows you to declare and allocate storage for a new string within a function, make your substring replacements, and then return a pointer to the new string for use back in the calling function.
For you circumstance, a simple declaration of a new string within a function and allocating twice the amount of storage as the original string is a reasonable approach to take. (you still must keep track of the number of bytes of memory you use, but you then have the ability to realloc additional memory if you should reach your original allocation limit) This process can continue and accommodate any number of strings and substitutions, up to the available memory on your system.
While there are a number of ways to approach the substitutions, simply searching the original string for each substring, and then copying the text up to the substring to the new string, then copying the replacement substring allows you to "inch-worm" from the beginning to the end of your original string making replacement substitutions as you go. The only challenge you have is keeping track of the number of characters used (so you can reallocate if necessary) and advancing your read position within the original from the beginning to the end as you go.
Your example somewhat complicates the process by needing to alternate between one of two replacement strings as you work your way down the string. This can be handled with a simple toggle flag. (a variable you alternate 0,1,0,1,...) which will then determine the proper replacement string to use where needed.
The ternary operator (e.g. test ? if_true : if_false; can help reduce the number of if (test) { if_true; } else { if_false; } blocks you have sprinkled through your code -- it's up to you. If the if (test) {} format is more readable to you -- use that, otherwise, use the ternary.
The following example takes the (1) original string, (2) the find substring, (3) the 1st replacement substring, and (4) the 2nd replacement substring as arguments to the program. It allocates for the new string within the strreplace() function, makes the substitutions requested and returns a pointer to the new string to the calling function. The code is heavily commented to help you follow along, e.g.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* replace all instances of 'find' in 's' with 'r1' and `r2`, alternating.
* allocate memory, as required, to hold string with replacements,
* returns allocated string with replacements on success, NULL otherwise.
*/
char *strreplace (const char *s, const char *find,
const char *r1, const char *r2)
{
const char *p = s, /* pointer to s */
*sp = s; /* 2nd substring pointer */
char *newstr = NULL, /* newsting pointer to allocate/return */
*np = newstr; /* pointer to newstring to fill */
size_t newlen = 0, /* length for newstr */
used = 0, /* amount of allocated space used */
slen = strlen (s), /* length of s */
findlen = strlen (find), /* length of find string */
r1len = strlen (r1), /* length of replace string 1 */
r2len = strlen (r2); /* length of replace string 2 */
int toggle = 0; /* simple 0/1 toggle flag for r1/r2 */
if (s == NULL || *s == 0) { /* validate s not NULL or empty */
fputs ("strreplace() error: input NULL or empty\n", stderr);
return NULL;
}
newlen = slen * 2; /* double length of s for newstr */
newstr = calloc (1, newlen); /* allocate twice length of s */
if (newstr == NULL) { /* validate ALL memory allocations */
perror ("calloc-newstr");
return NULL;
}
np = newstr; /* initialize newpointer to newstr */
/* locate each substring using strstr */
while ((sp = strstr (p, find))) { /* find beginning of each substring */
size_t len = sp - p; /* length to substring */
/* check if realloc needed? */
if (used + len + (toggle ? r2len : r1len) + 1 > newlen) {
void *tmp = realloc (newstr, newlen * 2); /* realloc to temp */
if (!tmp) { /* validate realloc succeeded */
perror ("realloc-newstr");
return NULL;
}
newstr = tmp; /* assign realloc'ed block to newstr */
newlen *= 2; /* update newlen */
}
strncpy (np, p, len); /* copy from pointer to substring */
np += len; /* advance newstr pointer by len */
*np = 0; /* nul-terminate (already done by calloc) */
strcpy (np, toggle ? r2 : r1); /* copy r2/r1 string to end */
np += toggle ? r2len : r1len; /* advance newstr pointer by r12len */
*np = 0; /* <ditto> */
p += len + findlen; /* advance p by len + findlen */
used += len + (toggle ? r2len : r1len); /* update used characters */
toggle = toggle ? 0 : 1; /* toggle 0,1,0,1,... */
}
/* handle segment of s after last find substring */
slen = strlen (p); /* get remaining length */
if (slen) { /* if not at end */
if (used + slen + 1 > newlen) { /* check if realloc needed? */
void *tmp = realloc (newstr, used + slen + 1); /* realloc */
if (!tmp) { /* validate */
perror ("realloc-newstr");
return NULL;
}
newstr = tmp; /* assign */
newlen += slen + 1; /* update (not required here, know why? */
}
strcpy (np, p); /* add final segment to string */
*(np + slen) = 0; /* nul-terminate */
}
return newstr; /* return newstr */
}
int main (int argc, char **argv) {
const char *s = NULL,
*find = NULL,
*r1 = NULL,
*r2 = NULL;
char *newstr = NULL;
if (argc < 5) { /* validate required no. or arguments given */
fprintf (stderr, "error: insufficient arguments,\n"
"usage: %s <find> <rep1> <rep2>\n", argv[0]);
return 1;
}
s = argv[1]; /* assign arguments to poitners */
find = argv[2];
r1 = argv[3];
r2 = argv[4];
newstr = strreplace (s, find, r1, r2); /* replace substrings in s */
if (newstr) { /* validate return */
printf ("oldstr: %s\nnewstr: %s\n", s, newstr);
free (newstr); /* don't forget to free what you allocate */
}
else { /* handle error */
fputs ("strreplace() returned NULL\n", stderr);
return 1;
}
return 0;
}
(above, the strreplace function uses pointers to walk ("inch-worm") down the original string making replacement, but you can use string indexes and index variables if that makes more sense to you)
(also note the use of calloc for the original allocation. calloc allocates and sets the new memory to all zero which can aid in insuring you don't forget to nul-terminate your string, but note any memory added by realloc will not be zeroed -- unless you manually zero it with memset or the like. The code above manually terminates the new string after each copy, so you can use either malloc or calloc for the allocation)
Example Use/Output
First example:
$ ./bin/str_substr_replace2 "^Hello world^" "^" "<s>" "</s>"
oldstr: ^Hello world^
newstr: <s>Hello world</s>
Second example:
$ ./bin/str_substr_replace2 "This is ~my house~ bud" "~" "<b>" "</b>"
oldstr: This is ~my house~ bud
newstr: This is <b>my house</b> bud
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/str_substr_replace2 "This is ~my house~ bud" "~" "<b>" "</b>"
==8962== Memcheck, a memory error detector
==8962== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==8962== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==8962== Command: ./bin/str_substr_replace2 This\ is\ ~my\ house~\ bud ~ \<b\> \</b\>
==8962==
oldstr: This is ~my house~ bud
newstr: This is <b>my house</b> bud
==8962==
==8962== HEAP SUMMARY:
==8962== in use at exit: 0 bytes in 0 blocks
==8962== total heap usage: 1 allocs, 1 frees, 44 bytes allocated
==8962==
==8962== All heap blocks were freed -- no leaks are possible
==8962==
==8962== For counts of detected and suppressed errors, rerun with: -v
==8962== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have any further questions.
I am trying to create a dynamic character "string pointer"/array and my code will not print values is the characters typed in exceed 249 characters. I am just wondering if there is a maximum return length for a character array/"string pointer".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *input() {
char *inpt;
char check;
int i;
int count;
i = 0;
count = 1;
check = '\0';
inpt = (char*)malloc(1);
while (check != '\n') {
check = getchar();
if (check == '\n') {
break;
} else {
inpt[i] = check;
i++;
count++;
inpt = realloc(inpt, count);
}
}
inpt[i] = '\0';
char *retrn;
retrn = inpt;
free(inpt);
printf("%d \n", i);
return retrn;
}
int main(int argc, char **argv) {
char *name;
printf("Please print name: \n");
name = input();
printf("%s is the name \n", name);
return 0;
}
The problem is not with the length of the string you attempt to return, but that you return a pointer to memory that no longer is allocated to you:
char *retrn;
retrn = inpt;
free(inpt);
return retrn;
When you do retrn = inpt you don't copy the memory, instead you have two pointers pointing to the same memory. Then you free that memory and return a pointer to the newly free'd memory. That pointer can't of course not be dereferenced and any attempt of doing that will lead to undefined behavior.
The solution is not any temporary variable like retrn, but to simply not free the memory in the input function. Instead return inpt and in the calling function (main in your case) you free the memory.
Continuing from my comment, there are a number of schemes to allocate memory dynamically. One thing you want to avoid from an efficiency standpoint is needlessly reallocating for every character. Rather than call realloc for every character added to name, allocate a reasonable number of characters to hold name, and if you reach that amount, then reallocate, doubling the current allocation size, update your variable holding the current size and keep going.
You already have an array index, so there is no need to keep a separate count. Just use your array index as the counter, insuring your have at least index + 1 characters available to provide space to nul-terminate inpt.
There is no need to keep separate pointers in input(). Just allocate for inpt and return inpt as the pointer to your block of memory when done. (don't forget to free (name); in main() which will free the memory you allocated in input.
Never realloc the pointer directly. (e.g. DON'T inpt = realloc (inpt, size);) If realloc fails it returns NULL causing the loss of a pointer to to the allocated block inpt referenced prior to the realloc call. Instead use a temporary pointer, validate that realloc succeeded, and then assign the new block to inpt (example below)
Putting it altogether, you could do something similar to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MEMSZ 32 /* initial allocation size (must be at least 1) */
char *input (void)
{
char *inpt = NULL, check;
size_t mem = MEMSZ, ndx = 0;
if (!(inpt = malloc (mem))) { /* allocate/validate mem chars */
fprintf (stderr, "input() error: virtual memory exhausted.\n");
return NULL;
}
/* you must check for EOF in addition to '\n' */
while ((check = getchar()) && check != '\n' && check != EOF)
{ /* check index + 1 to insure space to nul-terminate */
if (ndx + 1 == mem) { /* if mem limit reached realloc */
void *tmp = realloc (inpt, mem * 2); /* use tmp ptr */
if (!tmp) { /* validate reallocation */
fprintf (stderr, "realloc(): memory exhausted.\n");
break; /* on failure, preserve existing chars */
}
inpt = tmp; /* assign new block of memory to inpt */
mem *= 2; /* set mem to new allocaiton size */
}
inpt[ndx++] = check; /* assign, increment index */
}
inpt[ndx] = 0; /* nul-terminate */
return inpt; /* return pointer to allocated block */
}
int main (void)
{
char *name = NULL;
printf ("Please enter name: ");
if (!(name = input())) /* validate input() succeeded */
return 1;
printf ("You entered : %s\n", name);
free (name); /* don't forget to free name */
return 0;
}
Example Use/Output
$ ./bin/entername
Please enter name: George Charles Butte
You entered : George Charles Butte
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to write beyond/outside the bounds of your allocated block of memory, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/entername
==2566== Memcheck, a memory error detector
==2566== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==2566== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==2566== Command: ./bin/entername
==2566==
Please enter name: George Charles Butte
You entered : George Charles Butte
==2566==
==2566== HEAP SUMMARY:
==2566== in use at exit: 0 bytes in 0 blocks
==2566== total heap usage: 1 allocs, 1 frees, 32 bytes allocated
==2566==
==2566== All heap blocks were freed -- no leaks are possible
==2566==
==2566== For counts of detected and suppressed errors, rerun with: -v
==2566== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Let me know if you have any additional questions.
It's most likely due to using free memory. Your assignment input to retrn is not creating another copy. You'll get undefined behaviour, perhaps including what you are experiencing.
Is there a maximum return length for a character array in C
The maximum size of a character array is SIZE_MAX. SIZE_MAX is at least 65535.
I am just wondering if there is a maximum return length for a character array/"string pointer".
For a string, its maximum size is SIZE_MAX and the maximum length is SIZE_MAX - 1.
There are intrinsic limits for the size of an array:
available memory is limited: malloc() and realloc() may return NULL if the request cannot be honored due to lack of core memory. You should definitely check for malloc() and realloc() success.
system quotas may limit the amount of memory available to your process to a lower number than actual physical memory installed or virtual memory accessible in the system.
the maximum size for an array is the maximum value for the type size_t: SIZE_MAX which has a minimum value of 65535, but you use type int for your requests to malloc() or realloc(), that may have a smaller range than size_t. Type int is 32 bits on most current desktop systems where size_t may be 64 bits and available memory may be much more than 2GB. Use size_t instead of int.
Note however that your problem comes from a much simpler bug: you free the memory block you allocated for the string and return a copy of the pointer, which now points to freed memory. Accessing this memory has undefined behavior, which can be anything, including apparent correct behavior upto 249 bytes and failure beyond.
Note also that you should use type int for check and compare the return value of getchar() to EOF to avoid an endless loop if the input does not contain a newline (such as en empty file).
Here is a corrected version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *input(void) {
char *p = malloc(1); /* simplistic reallocation, 1 byte at a time */
size_t i = 0; /* use size_t for very large input */
int c; /* use int to detect EOF reliably */
if (p == NULL) {
return NULL; /* allocation error */
}
while ((c = getchar()) != EOF && c != '\n') {
char *newp = realloc(p, i + 2);
if (newp == NULL) {
free(p); /* avoid a memory leak */
return NULL; /* reallocation error */
}
p = newp;
p[i++] = c;
}
if (i == 0 && c == EOF) {
free(p);
return NULL; /* end of file */
}
p[i] = '\0';
return p;
}
int main(int argc, char **argv) {
char *name;
printf("Please print name: ");
name = input();
if (name == NULL) {
printf("input() returned NULL\n");
} else {
printf("%s is the name\n", name);
free(name);
}
return 0;
}
I have to get names with a known number of names from input as one string each separated by a space, I have to dynamically allocate memory for an array of strings where each string gets a name,
char** names;
char ch;
names = malloc(N*sizeof(char*); /*N is defined*/
for(i=0; i<N; i++) {
Now I have to allocate for each string without using a defined number:
i=0, j=0;
while ((ch=getchar) != '\n') {
while (ch != ' ') {
names[i][j++] = ch;
}
if (ch == ' ') {
names[i][j] = '\0';
i++}}
if (ch == '\n')
names[i][j] = '\0';
This is the classic question of how do I handle dynamic allocation and reallocation to store an unknown number of strings. (with a twist to separate each string into individual tokens before saving to the array) It is worth understanding this process in detail as it will serve as the basis for just about any any other circumstance where you are reading an unknown number of values (whether they are structs, floats, characters, etc...).
There are a number of different types of data structures you can employ, lists, trees, etc., but the basic approach is by creating an array of pointer-to-pointer-to-type (with type being char in this case) and then allocating space for, filling with data, and assigning the starting address for the new block of memory to each pointer as your data is read. The short-hand for pointer-to-pointer-to-type is simply double-pointer (e.g. char **array;, which is technically a pointer-to-pointer-to-char or pointer-to-char* if you like)
The general, and efficient, approach to allocating memory for an unknown number of lines is to first allocate a reasonably anticipated number of pointers (1 for each anticipated token). This is much more efficient than calling realloc and reallocating the entire collection for every token you add to your array. Here, you simply keep a counter of the number of tokens added to your array, and when you reach your original allocation limit, you simmply reallocate twice the number of pointers you currenly have. Note, you are free to add any incremental amount you choose. You can simply add a fixed amount each time, or you can use some scaled multiple of the original -- it's up to you. The realloc to twice the current is just one of the standard schemes.
What is "a reasonably anticipated number of pointers?" It's no precise number. You simply want to take an educated guess at the number of tokens you roughtly expect and use that as an initial number for allocating pointers. You wouldn't want to allocate 10,000 pointers if you only expect 100. That would be horribly wasteful. Reallocation will take care of any shortfall, so a rough guess is all that is needed. If you truly have no idea, then allocate some reasonable number, say 64 or 128, etc.. You can simply declare the limit as a constant at the beginning of your code, so it is easily adjusted. e.g.:
#declare MAXPTR 128
or accomplish the same thing using an anonymous enum
enum { MAXPTR = 128 };
When allocating your pointers originally, and as part of your reallocation, you can benefit by setting each pointer to NULL. This is easily accomplished for the original allocation. Simply use calloc instead of malloc. On reallocation, it requires that you set all new pointers allocated to NULL. The benefit it provides is the first NULL acts as a sentinel indicating the point at which your valid pointers stop. As long as you insure you have at least one NULL preserved as a sentinel, you can iterate without the benefit of knowing precise number of pointers filled. e.g.:
size_t i = 0;
while (array[i]) {
... do your stuff ...
}
When you are done using the allocated memory, you want to insure you free the memory. While in a simple piece of code, the memory is freed on exit, get in the habit of tracking the memory you allocate and freeing it when it is no longer needed.
As for this particular task, you will want to read a line of unknown number of characters into memory and then tokenize (separate) the string into tokens. getline will read and allocate memory sufficient to hold any size character string. You can do the same thing with any of the other input functions, you just have to code the repeated checks and reallocations yourself. If getline is available (it is in every modern compier), use it. Then it is just a matter of separating the input into tokens with strtok or strsep. You will then want to duplicate the each token to preserve each token in its own block of memory and assign the location to your array of tokens. The following provides a short example.
Included in the example are several helper functions for opening files, allocating and reallocating. All they do is simple error checking which help keep the main body of your code clean and readable. Look over the example and let me know if you have any questions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 64 /* initial number of pointers */
/* simple helper/error check functions */
FILE *xfopen (const char *fn, const char *mode);
void *xcalloc (size_t n, size_t s);
void *xrealloc_dp (void *ptr, size_t *n);
int main (int argc, char **argv) {
char **array = NULL;
char *line = NULL;
size_t i, idx = 0, maxl = MAXL, n = 0;
ssize_t nchr = 0;
FILE *fp = argc > 1 ? xfopen (argv[1], "r") : stdin;
array = xcalloc (maxl, sizeof *array); /* allocate maxl pointers */
while ((nchr = getline (&line, &n, fp)) != -1)
{
while (nchr > 0 && (line[nchr-1] == '\r' || line[nchr-1] == '\n'))
line[--nchr] = 0; /* strip carriage return or newline */
char *p = line; /* pointer to use with strtok */
for (p = strtok (line, " \n"); p; p = strtok (NULL, " \n")) {
array[idx++] = strdup (p); /* allocate & copy */
/* check limit reached - reallocate */
if (idx == maxl) array = xrealloc_dp (array, &maxl);
}
}
free (line); /* free memory allocated by getline */
if (fp != stdin) fclose (fp);
for (i = 0; i < idx; i++) /* print all tokens */
printf (" array[%2zu] : %s\n", i, array[i]);
for (i = 0; i < idx; i++) /* free all memory */
free (array[i]);
free (array);
return 0;
}
/* fopen with error checking */
FILE *xfopen (const char *fn, const char *mode)
{
FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
// return NULL;
exit (EXIT_FAILURE);
}
return fp;
}
/* simple calloc with error checking */
void *xcalloc (size_t n, size_t s)
{
void *memptr = calloc (n, s);
if (memptr == 0) {
fprintf (stderr, "xcalloc() error: virtual memory exhausted.\n");
exit (EXIT_FAILURE);
}
return memptr;
}
/* realloc array of pointers ('memptr') to twice current
* number of pointer ('*nptrs'). Note: 'nptrs' is a pointer
* to the current number so that its updated value is preserved.
* no pointer size is required as it is known (simply the size
* of a pointer
*/
void *xrealloc_dp (void *ptr, size_t *n)
{
void **p = ptr;
void *tmp = realloc (p, 2 * *n * sizeof tmp);
if (!tmp) {
fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
exit (EXIT_FAILURE);
}
p = tmp;
memset (p + *n, 0, *n * sizeof tmp); /* set new pointers NULL */
*n *= 2;
return p;
}
Input File
$ cat dat/captnjack.txt
This is a tale
Of Captain Jack Sparrow
A Pirate So Brave
On the Seven Seas.
Output
$ ./bin/getline_strtok <dat/captnjack.txt
array[ 0] : This
array[ 1] : is
array[ 2] : a
array[ 3] : tale
array[ 4] : Of
array[ 5] : Captain
array[ 6] : Jack
array[ 7] : Sparrow
array[ 8] : A
array[ 9] : Pirate
array[10] : So
array[11] : Brave
array[12] : On
array[13] : the
array[14] : Seven
array[15] : Seas.
Memory/Error Check
In any code your write that dynamically allocates memory, you have 2 responsibilites regarding any block of memory allocated: (1) always preserves a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed. It is imperative that you use a memory error checking program to insure you haven't written beyond/outside your allocated block of memory and to confirm that you have freed all the memory you have allocated. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, there is no excuse not to do it. There are similar memory checkers for every platform. They are all simple to use. Just run your program through it.
$ valgrind ./bin/getline_strtok <dat/captnjack.txt
==26284== Memcheck, a memory error detector
==26284== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==26284== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==26284== Command: ./bin/getline_strtok
==26284==
array[ 0] : This
array[ 1] : is
<snip>
array[14] : Seven
array[15] : Seas.
==26284==
==26284== HEAP SUMMARY:
==26284== in use at exit: 0 bytes in 0 blocks
==26284== total heap usage: 18 allocs, 18 frees, 708 bytes allocated
==26284==
==26284== All heap blocks were freed -- no leaks are possible
==26284==
==26284== For counts of detected and suppressed errors, rerun with: -v
==26284== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
What you want to confirm each time is "All heap blocks were freed -- no leaks are possible" and "ERROR SUMMARY: 0 errors from 0 contexts".
How about growing the buffer gradually, for example, by doubling the size of buffer when the buffer becomes full?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char *read_string(void) {
size_t allocated_size = 2;
size_t read_size = 0;
char *buf = malloc(allocated_size); /* allocate initial buffer */
if (buf == NULL) return NULL;
for(;;) {
/* read next character */
int input = getchar();
if (input == EOF || isspace(input)) break;
/* if there isn't enough buffer */
if (read_size >= allocated_size - 1) {
/* allocate new buffer */
char *new_buf = malloc(allocated_size *= 2);
if (new_buf == NULL) {
/* failed to allocate */
free(buf);
return NULL;
}
/* copy data read to new buffer */
memcpy(new_buf, buf, read_size);
/* free old buffer */
free(buf);
/* assign new buffer */
buf = new_buf;
}
buf[read_size++] = input;
}
buf[read_size] = '\0';
return buf;
}
int main(void) {
int N = 5;
int i;
char** names;
names = malloc(N*sizeof(char*));
if(names == NULL) return 1;
for(i=0; i<N; i++) {
names[i] = read_string();
}
for(i = 0; i < N; i++) {
puts(names[i] ? names[i] : "NULL");
free(names[i]);
}
free(names);
return 0;
}
Note: They say you shouldn't cast the result of malloc() in C.
For a known number of strings, you have allocated the char ** correctly:
char** names;
names = (char**) malloc(N*sizeof(char*));
Note, because the cast is not necessary in C, you could write it like this:
names = malloc(N*sizeof(char*));
For allocating memory as you read the file, for strings of unknown length, use the following approach:
allocate a buffer using [m][c]alloc of a known starting size (calloc is cleaner)
read into the buffer until you run out of space.
use realloc to increase the size of buffer by some increment (double it)
repeat steps 1 through 3 until file is read
Also, when working with buffers of unknown length, and you would like its contents to be pre-set, or zeroed, consider using calloc() over malloc(). It is a cleaner option.
When you say,
char** names;
char ch;
names = malloc(N*sizeof(char*));
You created a names variable which is double pointer capable of storing address of strings multiple N times.
Ex: if you have 32 strings, then N is 32.
So, 32* sizeof(char*)
and sizeof char* is 4 bytes
Hence, 128 bytes will be allocated
After that you did this,
names[i][j++] = ch;
The above expression is wrong way to use.
Because, you are trying to assign char data to address variables.
You need to create sub memories for memory address variables name .
Or you need to assign address of each sub string from main string.
use readline() or getline() to acquire a pointer to a memory allocation that contains the data.
Then use something like sscanf() or strtok() to extract the individual name strings into members of an array.