it seems like i did not really understand how the memory allocation with pointers works.
Quick example:
I got a structure,
struct Friends{
char *firstname;
char *lastname;
};
if I do allocate memory now, it will get me
2x sizeof(char) = 2x 1Byte
but, doesnt the free memory I need depend on how many characters I fill it with?
example:
char array[10] needs 10x sizeof(char), 1byte for each character?
Everywhere I look they allocate the memory, before they know how much they will fill the structure with.
I got a structure,
struct Friends{
char *firstname;
char *lastname;
};
if I do allocate memory now, it will get me
2x sizeof(char) = 2x 1Byte
Instead of char's, you are allocating pointers here sizeof(char *). Depending on the system, those are 4 bytes (32-bit) or 8 bytes (64-bit) each.
So, if you want data where your pointers point to, you will have to allocate that, with malloc() for example, and free() them later.
Or do something like:
struct Friends{
char firstname[20];
char lastname[20];
};
But make sure your strings end with a \0 char.
Everywhere I look they allocate the memory, before they know how much
they will fill the structure with.
Yes and no.
struct Friends {
char *firstname;
char *lastname;
};
It all depends on how you intend to use your structure. There are multiple ways you can use struct Friends. You can declare a static instance of the struct, and then simply assign the address of existing strings to your firstname and lastname member pointers, e.g.:
int main (void) {
Struct Friends friend = {{Null}, {NULL]};
/* simple assignment of pointer address
* (memory at address must remain valid/unchanged)
*/
friend.firstname = argc > 1 ? argv[1] : "John";
friend.lastname = argc > 2 ? argv[2] : "Smith";
printf ("\n name: %s %s\n\n", friend.firstname, friend.lastname);
However, in most cases, you will want to create a copy of the information and store a copy of the string for the firstname and lastname members. In that case you need to allocate a new block of memory for each pointer and assign the starting address for each new block to each pointer. Here you now know what your strings are, and you simply need to allocate memory for the length of each string (+1 for the nul-terminating character) e.g.:
int main (int argc, char **argv) {
/* declare static instance of struct */
struct Friends friend = {NULL, NULL};
char *first = argc > 1 ? argv[1] : "John";
char *last = argc > 2 ? argv[2] : "Smith";
/* determine the length of each string */
size_t len_first = strlen (first);
size_t len_last = strlen (last);
/* allocate memory for each pointer in 'friend' */
friend.firstname = malloc (len_first * sizeof *friend.firstname + 1);
friend.lastname = malloc (len_last * sizeof *friend.lastname + 1);
You then need only copy each string to the address for each member:
/* copy names to new memory referenced by each pointer */
strcpy (friend.firstname, first);
strcpy (friend.lastname, last);
Finally, once you are done using the memory allocated, you must free the memory with free. note: you can only free memory that you have previously allocated with malloc or calloc. Never blindly attempt to free memory that has not been allocated that way. To free the members, all you need is:
/* free allocated memory */
free (friend.firstname);
free (friend.lastname);
A short example putting all the pieces together is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Friends {
char *firstname;
char *lastname;
};
int main (int argc, char **argv) {
/* declare static instance of struct */
struct Friends friend = {NULL, NULL};
char *first = argc > 1 ? argv[1] : "John";
char *last = argc > 2 ? argv[2] : "Smith";
/* determine the length of each string */
size_t len_first = strlen (first);
size_t len_last = strlen (last);
/* allocate memory for each pointer in 'friend' */
friend.firstname = malloc (len_first * sizeof *friend.firstname + 1);
friend.lastname = malloc (len_last * sizeof *friend.lastname + 1);
/* copy names to new memory referenced by each pointer */
strcpy (friend.firstname, first);
strcpy (friend.lastname, last);
printf ("\n name: %s %s\n\n", friend.firstname, friend.lastname);
/* free allocated memory */
free (friend.firstname);
free (friend.lastname);
return 0;
}
Always compile with warnings enabled, for example:
gcc -Wall -Wextra -o bin/struct_dyn_alloc struct_dyn_alloc.c
(if not using gcc, then your compiler will have similar options)
Anytime you dynamically allocate memory in your code, run in though a memory error checking program to insure you are not misusing the allocated blocks of memory in some way, and to confirm all memory has been freed. It is simple to do. All OS's have some type of checker. valgrind is the normal choice on Linux. For example:
$ valgrind ./bin/struct_dyn_alloc
==14805== Memcheck, a memory error detector
==14805== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==14805== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==14805== Command: ./bin/struct_dyn_alloc
==14805==
name: John Smith
==14805==
==14805== HEAP SUMMARY:
==14805== in use at exit: 0 bytes in 0 blocks
==14805== total heap usage: 2 allocs, 2 frees, 11 bytes allocated
==14805==
==14805== All heap blocks were freed -- no leaks are possible
==14805==
==14805== For counts of detected and suppressed errors, rerun with: -v
==14805== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
So with types like yours above, you have basically a two-step allocation process:
First, you allocate an object of type struct Friends, which contains space for two pointers;
Second, you allocate memory for the objects that each member of struct Friends will point to.
Quick and dirty example:
struct Friends *addFriend( const char *firstName, const char *lastName )
{
/**
* First, allocate an instance of `struct Friends`, which will contain
* enough space to store two pointers to `char`
*/
struct Friends *f = malloc( sizeof *f ); // sizeof *f == sizeof (struct Friends)
if ( f )
{
/**
* Allocate space to store a *copy* of the contents of the firstName
* parameter, assign the resulting pointer to the firstname member of
* the struct instance.
*/
f->firstname = malloc( strlen( firstName ) + 1 );
if ( f->firstname )
strcpy( f->firstname, firstName );
/**
* Do the same for lastName
*/
f->lastName = malloc( strlen( lastName ) + 1 );
if ( f->lastname )
strcpy( f->lastname, lastName );
}
return f;
}
If we call this function as
struct Friends newFriend = addFriend( "John", "Bode" );
we get something like the following in memory:
+---+ +---+ +---+---+---+---+---+
newFriend:| | --> newFriend->firstname: | | ---->|'J'|'o'|'h'|'n'| 0 |
+---+ +---+ +---+---+---+---+---+
newFriend->lastname: | | -+
+---+ | +---+---+---+---+---+
+-->|'B'|'o'|'d'|'e'| 0 |
+---+---+---+---+---+
Here's how it plays out on my system:
Item Address 00 01 02 03
---- ------- -- -- -- --
newFriend 0x7fffe6910368 10 20 50 00 ..P.
0x7fffe691036c 00 00 00 00 ....
*newFriend 0x502010 30 20 50 00 0.P.
0x502014 00 00 00 00 ....
0x502018 50 20 50 00 P.P.
0x50201c 00 00 00 00 ....
newFriend->firstname 0x502030 4a 6f 68 6e John
newFriend->lastname 0x502050 42 6f 64 65 Bode
The newFriend pointer variable lives at address 0x007fffe6910368. It points to an object of type struct Friends which lives at address 0x502010. This object is large enough to store two pointer values; newFriend->firstname lives at address 0x5020101 and points to the string "John", which lives at address 0x502030. newFriend->lastname lives at address 0x502018 and points to the string "Bode", which lives at address 0x502050.
To deallocate, you free the members before freeing the struct object:
void deleteFriend( struct Friends *f )
{
free( f->firstname );
free( f->lastname );
free( f );
}
It doesn't matter what order you free f->firstname and f->lastname with respect to each other; what matters is that you have to delete both of them before you can delete f. Freeing f won't free what f->firstname and f->lastname point to2.
Note that this all assumes I'm being given data with a known size (the firstName and lastName parameters in addFriend); I use the lengths of those input strings to determine how much space I need to allocate.
Sometimes you do not know ahead of time how much space you need to set aside. The usual approach is to allocate some initial amount of storage and to extend it as necessary using the realloc function. For example, suppose we have code to read a single line of text terminated by a newline character from an input stream. We want to be able to handle lines of any length, so we start out by allocating enough space to handle most cases, and if we need more, we double the size of the buffer as necessary:
size_t lineSize = 80; // enough for most cases
char *line = calloc( lineSize, sizeof *line );
char buffer[20]; // input buffer for reading from stream
/**
* Keep reading until end of file or error.
*/
while ( fgets( buffer, sizeof buffer, stream ) != NULL )
{
if ( strlen( line ) + strlen( buffer ) >= lineSize )
{
/**
* There isn't enough room to store the new string in the output line,
* so we double the output line's size.
*/
char *tmp = realloc( line, 2 * lineSize );
if ( tmp )
{
line = tmp;
lineSize *= 2;
}
else
{
/**
* realloc call failed, handle as appropriate. For this
* example, we break out of the loop immediately
*/
fprintf( stderr, "realloc error, breaking out of loop\n" );
break;
}
}
strcat( line, buffer );
/**
* If we see a newline in the last input operation, break out of the
* loop.
*/
if ( strchr( buffer, '\n' ) )
break;
}
1. The address of the first element of a struct is the same as the address of the whole struct object; C doesn't store any kind of metadata before the first struct member.
2. Note that you can only call free on an object that was allocated with malloc, calloc, or realloc; you would not call free on a pointer that points to a string literal or another array.
If i understood your problem correctly, you want to see the memory allocated for firstname and lastname based on your requirement of the future storage.
I'm afraid, that is not possible.
When you got a variable of type struct Friends, say struct Friends F;, F.firstname and F.lastname will be pointers but they will not be pointing to any valid memory. You need to perform the allocation for F.firstname and F.lastname separately. Something like
F.firstname = malloc(32);
F.lastname = malloc(32); //perform NULL check too
and then you can actually make use of F.firstname and F.lastname
Everywhere I look they allocate the memory, before they know how much they will fill the structure with.
If I understood properly you are asking how we can allocate memory before they know how much space we gonna use.
Consider the following structure:
struct foo
{
char bar;
char foobar;
};
struct foo *temp = (struct foo *) malloc(sizeof(struct foo));
Here 2 * 1 = 2 bytes will be allocated dynamically whether you store something in bar and foobar variables or not.
If you don't store anything then the variable (memory location) contains grabage value.
Related
When we allocating memory spaces for a string, do the following 2 ways give the same result?
char *s = "abc";
char *st1 = (char *)malloc(sizeof(char)*strlen(s));
char *st2 = (char *)malloc(sizeof(s));
In other words, does allocate the memory based on the size of its characters give the same result as allocating based on the size of the whole string?
If I do use the later method, is it still possible for me to add to that memory spaces character by character such as:
*st = 'a';
st++;
*st = 'b';
or do I have to add a whole string at once now?
Let's see if we can't get you straightened out on your question and on allocating (and reallocating) storage. To begin, when you declare:
char *s = "abc";
You have declared a pointer to char s and you have assigned the starting address for the String Literal "abc" to the pointer s. Whenever you attempt to use sizeof() on a_pointer, you get sizeof(a_pointer) which is typically 8-bytes on x86_64 (or 4-bytes on x86, etc..)
If you take sizeof("abc"); you are taking the size of a character array with size 4 (e.g. {'a', 'b', 'c', '\0'}), because a string literal is an array of char initialized to hold the string "abc" (including the nul-terminating character). Also note, that on virtually all systems, a string literal is created in read-only memory and cannot be modified, it is immutable.
If you want to allocate storage to hold a copy of the string "abc", you must allocate strlen("abc") + 1 characters (the +1 for the nul-terminating character '\0' -- which is simply ASCII 0, see ASCII Table & Description.
Whenever you allocate 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. So if you allocate for char *st = malloc (len + 1); characters, you do not want to iterate with the pointer st (e.g. no st++). Instead, declare a second pointer, char *p = st; and you are free to iterate with p.
Also, in C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?.
If you want to add to an allocation, you use realloc() which will create a new block of memory for you and copy your existing block to it. When using realloc(), you always reallocate using a temporary pointer (e.g. don't st = realloc (st, new_size);) because if when realloc() fails, it returns NULL and if you assign that to your pointer st, you have just lost the original pointer and created a memory leak. Instead, use a temporary pointer, e.g. void *tmp = realloc (st, new_size); then validate realloc() succeeds before assigning st = tmp;
Now, reading between the lines that is where you are going with your example, the following shows how that can be done, keeping track of the amount of memory allocated and the amount of memory used. Then when used == allocated, you reallocate more memory (and remembering to ensure you have +1 bytes available for the nul-terminating character.
A short example would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define THISMANY 23
int main (void) {
char *s = "abc", *st, *p; /* string literal and pointer st */
size_t len = strlen(s), /* length of s */
allocated = len + 1, /* number of bytes in new block allocated */
used = 0; /* number of bytes in new block used */
st = malloc (allocated); /* allocate storage for copy of s */
p = st; /* pointer to allocate, preserve st */
if (!st) { /* validate EVERY allocation */
perror ("malloc-st");
return 1;
}
for (int i = 0; s[i]; i++) { /* copy s to new block of memory */
*p++ = s[i]; /* (could use strcpy) */
used++; /* advance counter */
}
*p = 0; /* nul-terminate copy */
for (size_t i = 0; i < THISMANY; i++) { /* loop THISMANY times */
if (used + 1 == allocated) { /* check if realloc needed (remember '\0') */
/* always realloc using temporary pointer */
void *tmp = realloc (st, 2 * allocated); /* realloc 2X current */
if (!tmp) { /* validate EVERY reallocation */
perror ("realloc-st");
break; /* don't exit, original st stil valid */
}
st = tmp; /* assign reallocated block to st */
allocated *= 2; /* update allocated amount */
}
*p++ = 'a' + used++; /* assign new char, increment used */
}
*p = 0; /* nul-terminate */
printf ("result st : %s\n" /* output final string, length, allocated */
"length st : %zu bytes\n"
"final size : %zu bytes\n", st, strlen(st), allocated);
free (st); /* don't forget to free what you have allocated */
}
Example Use/Output
$ ./bin/sizeofs
result st : abcdefghijklmnopqrstuvwxyz
length st : 26 bytes
final size : 32 bytes
Look things over and let me know if this answered your questions, and if not, leave a comment and I'm happy to help further.
If you are still shaky on what a pointer is, and would like more information, here are a few links that provide basic discussions of pointers that may help. Difference between char pp and (char) p? and Pointer to pointer of structs indexing out of bounds(?)... (ignore the titles, the answers discuss pointer basics)
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
So I'm trying to make a char**, I fully understand how it works in the background and all that stuff but I don't seem to understand how to write the code for it. I want to make a pointer to an array of chars which has a name in it. I need help with storing a string in it (using strcpy() ) and print it after that.
char** name = (char**)malloc((strlen("MyName") + 1) * sizeof(char*));
strcpy(name, "MyName"); // I get an error right here
If you really want a pointer to an char array, you could do the following:
char** name = (char**)malloc(sizeof(char*)); //initialize the pointer
*name = (char*)malloc((strlen("MyName") + 1) * sizeof(char)); //initialize the array
strcpy(*name, "MyName");
So I'm trying to make a char**, I fully understand how it works in the
background and all that stuff but I don't seem to understand how to
write the code for it.
Umm... No, not quite.
To declare a pointer-to-char, you simply decalre:
char *name = malloc (strlen("MyName") + 1);
Why? When you make your call to malloc, malloc allocates a block of memory providing strlen("MyName") + 1 bytes and returns the starting address to that block of memory -- which you assign to name. You then can copy "MyName" to name (with 1-byte remaining for the nul-terminating character). The approach would be:
size_t len = strlen ("MyName");
char *name = malloc (len + 1); /* allocate len + 1 bytes */
if (name == NULL) { /* validate EVERY allocation */
perror ("malloc-name");
/* handle error by returning or exiting */
}
memcpy (name, "MyName", len + 1); /* no need to scan again for \0 */
/* do something with name - here */
free (name); /* don't forget to free name when you are done */
What then does char** do?
When you are dealing with a pointer-to-pointer-to-char, you must first allocate for some number of pointers, then you can allocate and assign a block of memory to each of the pointers and use each pointer just as you have used name above.
For example:
/* array of ponters to string-literals for your source of strings */
char *band[] = { "George", "Ringo", "Paul", "John" };
char **names;
size_t nmembers = sizeof band / sizeof *band;
/* allocate nmembers pointers */
names = malloc (nmembers * sizeof *names);
if (names == NULL) { /* validate EVERY allocation */
perror ("malloc-name_pointers");
/* handle error by returning or exiting */
}
/* now loop allocating for each name and copy */
for (size_t i = 0; i < nmembers; i++) {
size_t len = strlen (band[i]); /* get length */
names[i] = malloc (len + 1); /* allocate */
if (names[i] == NULL) { /* validate EVERY allocation */
perror ("malloc-names[i]");
/* handle error by returning or exiting */
}
memcpy (names[i], band[i], len + 1);/* no need to scan again for \0 */
}
/* output each */
for (size_t i = 0; i < nmembers; i++)
printf ("member[%zu]: %s\n", i + 1, names[i]);
Freeing names is a two step process. You must free the memory allocated to each of the names pointers and then free the pointers themselves, e.g.
for (size_t i = 0; i < nmembers; i++)
free (names[i]); /* free each allocated names[i] */
free (names); /* free pointers */
Now hopefully you more closely "... fully understand how it works". Let me know if you have any questions.
First thing you should understand is that declaring a variable as a single pointer or a double pointer (or any other n pointer) doesn't actually tell whether the underlying variable holds a single value or an array of values.
Single pointer points to a memory address on which actual value is stored. Double pointer points to a memory address on which single pointer is stored, and so on.
Now, to make a pointer to an array of char pointers you can use a single char pointer (char*) but I recommend to use double char pointer (char**) for maintainability purposes.
Consider the following code:
char** names = (char**)malloc(100 * sizeof(char*));
It will allocate memory space for 100 char pointers (char*) on heap and return you a double pointer (char**) to the first single pointer (char*) in that memory space. This means you will be able to save 100 char pointers (or 100 names in your case) inside that memory space. Then you can use them like this:
char* name0 = "First Name"; // Saved on stack
char* name1 = malloc((strlen("Second Name") + 1) * sizeof(char)); // Saved on heap
strcpy(name1, "Second Name");
names[0] = name0;
names[1] = name1;
Also, please note that when saving a string on heap you need to add one more place for null character (manually).
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.
char *t = malloc(2);
t = "as";
t = realloc(t,sizeof(char)*6);
I am getting error "invalid pointer: 0x080488d4 *"..
I am getting strange errors in using memory allocation functions. Is there any good tuts/guides which could explain me memory allocation functions.
I am using linux..
Please help..
This is your problem:
char *t = malloc(2);
t = "as";
You probably thought this would copy the two-character string "as" into the buffer you just allocated. What it actually does is throw away (leak) the buffer, and change the pointer to instead point to the string constant "as", which is stored in read-only memory next to the machine code, not on the malloc heap. Because it's not on the heap, realloc looks at the pointer and says "no can do, that's not one of mine". (The computer is being nice to you by giving you this error; when you give realloc a pointer that wasn't returned by malloc or realloc, the computer is allowed to make demons fly out of your nose if it wants.)
This is how to do what you meant to do:
char *t = malloc(3);
strcpy(t, "as");
Note that you need space for three characters, not two, because of the implicit NUL terminator.
By the way, you never need to multiply anything by sizeof(char); it is 1 by definition.
That is not how you assign strings in C.
The correct syntax is:
char* t = malloc(3); // Reserve enough space for the null-terminator \0
strncpy(t, "as", 3);
// Copy up to 3 bytes from static string "as" to char* t.
// By specifying a maximum of 3 bytes, prevent buffer-overruns
Allocating 2-bytes is NOT enough for "as".
C-strings have a 1-byte null-terminator, so you need at least 3 bytes to hold "as\0".
(\0 represents the null-terminator)
The code you wrote: t = "as"; makes the pointer t "abandon" the formerly allocated memory, and instead point to the static string "as". The memory allocated with malloc is "leaked" and cannot be recovered (until the program terminates and the OS reclaims it).
After this, you can call realloc as you originally did.
However, you should not do t = realloc(t,6);. If realloc fails for any reason, you've lost your memory.
The preferred method is:
new_t = realloc(t, 6);
if (new_t != NULL) // realloc succeeded
{ t = new_t;
}
else
{ // Error in reallocating, but at least t still points to good memory!
}
Your code reassigns t, making it point elsewhere
char *t = malloc(2); //t=0xf00ba12
t = "as"; //t=0xbeefbeef
t = realloc(t,sizeof(char)*6); //confused because t is 0xbeefbeef, not 0xf00b412.
Instead use strcpy
char *t = malloc(3); //don't forget about the '\0'
strcpy(t, "as");
t = realloc(t, 6); //now the string has room to breathe
First off, don't do that:
char *t = malloc(2);
Do this instead:
char *t = malloc(2 * sizeof(char));
/* or this: */
char *t = calloc(2, sizeof(char));
It may not seem worth the effort, but otherwise you may run into problems later when you deal with types larger than 1 byte.
In this line:
t = "as";
You're assigning the address of the string literal "as", so your pointer no longer points to the memory you allocated. You need to copy the contents of the literal to your allocated memory:
char *t = calloc(3, sizeof(char));
/* "ar" is 3 char's: 'a', 'r' and the terminating 0 byte. */
strncpy(t, "ar", 3);
/* then later: */
t = realloc(t,sizeof(char)*6);
You can also just use strdup, which is safer:
#include <string.h>
char *t = strdup("ar");
t = realloc(t,sizeof(char)*6);
And don't forget to free the memory
free(t);
char *t = malloc(2);
this means you have created a pointer to a memory location that can hold 2 bytes
+-+-+
t -> | | |
+-+-+
when you do
t = "as";
now you made t point to somewhere else than what it originally was pointing to. now it no longer points to the heap
t = realloc(t,sizeof(char)*6);
now you are taking the pointer pointing to read only memory and try to realloc it.
when you use malloc you allocate space on the heap. t in this case is a pointer to that location, an address of where the block is.
in order to put something in that spot you need to copy the data there by dereferencing t, this is done by writing * in front of t:
*t = 'a'; // now 'a' is where t points
*(t+1)='s'; // now 's' is behind a, t still pointing to 'a'
however in C, a string is always terminated with a 0 (ASCII value) written as '\0' so in order to make it a string you need to append a \0
+-+-+--+
t -> |a|s|\0|
+-+-+--+
in order to do this you need to malloc 3 bytes instead, than you can add the \0 by writing *(t+2)='\0';
now t can be treated as pointing to a string and used in functions that takes strings as arguments e.g. strlen( t ) returns 2