Realloc doesn't work in a while loop - c

I need help with my C assignment. The task is to write a program, which takes string input of unknown length. Also I need to separate words, that's why I use char**. Program stops taking input, when a special word appears. You can see my code bellow:
char **words=NULL;
maxWords=1;
numberOfWords=0;
words=calloc(maxWords,sizeof(char **));
input=malloc(max*sizeof(char *));
words[numberOfWords]=calloc(max,sizeof(char*));
while(stopValue){
while((c=getchar())!='\n' && c!=' ' && c!=EOF){
input[i++]=c;
if(i==currentSize){
currentSize=i+max;
input=realloc(input,currentSize);
words[numberOfWords]=realloc(words[numberOfWords],currentSize);
}
}
input[i]='\0';
if(strcmp(input,terminator)==0){
break;
}
strcpy( words[numberOfWords],input);
numberOfWords++;
maxWords++;
words=realloc(words,maxWords);
words[numberOfWords]=calloc(max,sizeof(char*));
currentSize=max;
i=0;
input=realloc(input,max);
}
It works good, when I have only 2-3 words of input. But it fails when there are more. I think that the problem is with words=realloc(words,maxWords); this line, but I don't know what exactly.
Any help, please?

The second argument to calloc() should be the size of what the pointer points to, i.e. the pointed-to-type, not the size of the pointer-type itself.
For example, suppose you want to allocate space for 10 int, assigning the result to an int *p, any of the following would be proper syntax and exhibit defined behavior:
int *a = malloc(10 * sizeof(int));
int *b = calloc(10, sizeof(int));
int *c = realloc(NULL, 10*sizeof(int))
int *d = malloc(10 * sizeof *d);
int *e = calloc(10, sizeof *e);
int *f = realloc(NULL, 10 * sizeof *f);
A pointer-to-pointer acts no differently. If you want to allocate a sequence of pointer-to-char, identical syntax applies:
char **a = malloc(10 * sizeof(char*));
char **b = calloc(10, sizeof(char*));
char **c = realloc(NULL, 10*sizeof(char*))
char **d = malloc(10 * sizeof *d);
char **e = calloc(10, sizeof *e);
char **f = realloc(NULL, 10 * sizeof *f);
Notice that not just the syntax, but the actual code of the last three in both of the above lists is identical, save for the pointer-type itself (the first is pointer-to-int, the second is pointer-to-pointer-to-char). That syntax takes advantage of how the sizeof operator (it isn't a function or macro; it's an operator) can be used against a variable rather than a type.
That said, words in your code is a pointer-to-pointer-to-char. I should be allocated using similar syntax for proper sizing. Either of the following will work correctly:
char **words = calloc(maxwords, sizeof(char*)); // right, uses specific type
char **words = calloc(maxwords, sizeof *words); // right, gets size from var type
Both do the same thing: allocate a buffer properly aligned and sized to accommodate maxwords number of char*, exactly what you would want for storing pointers to strings.
This problem is replicated again when you do this:
words[numberOfWords] = calloc(max, sizeof(char*)); // wrong
Again, words is char**, so words[anything] is char* and as such, should be assigned an allocation based on the size of the pointed-to-type: char. Either of the following will do so:
words[numberOfWords] = calloc(max, sizeof(char)); // right, or...
words[numberOfWords] = calloc(max, sizeof **words); // right
Ok all of that said, your suspicion that this is wrong:
words = realloc(words, maxWords);
is well-founded. The realloc function takes a byte count as the second parameter. You're passing a count of pointers, but not including the size of each pointer in the number of bytes requested. Using the syntax described earlier, this could be done as:
words = realloc(words, maxWords * sizeof *words);
or
words = realloc(words, maxWords * sizeof(char*));
Either will work, and now includes the size of each pointer, thereby calculating the correct number of bytes to request.
Best of luck.

Related

Calling malloc and storing return value in double pointer?

char **init(int n) {
char **result;
result = malloc(n * sizeof(char));
return result;
}
I need help understanding whether the 3rd line is a bug or not. The call to malloc() will create N contiguous blocks on memory on the heap each big enough to store a single character, and it will return a void ptr (base address of the array). However, result is a pointer to a pointer, so it would need to store the address of another pointer which is not the case here?
Maybe you are looking to do something like this:
char *init(unsigned int n) {
char *result;
/* allocate the memory */
result = malloc(n * sizeof(char));
return result;
}
this will allocate memory to store n contiguous characters.
you could reduce the code to:
char *init(int n) {
return malloc(n * sizeof(char));
}
or instead of calling this function you could just directly do:
malloc(n * sizeof(char));
or you could create a macro
#define INIT_CHAR_ARR(n) malloc((n) * sizeof(char))
if you want n contiguous character pointers:
malloc(n * sizeof(char*))
It would help us help you if you explained your end goal, maybe there is a better way to do what you are doing.

Memory allocation for a char ** pointer in C

I have to maintain an array of strings, which each string will contain the IP address of a neighbor. For some reason i need to maintain them as strings.
typedef struct _neighbors
{
int num_neigbors;
char **neighbor_address;
} neighbors;
Assume i have two neighbors to add.
I view char ** neighbor_address as an array of char * pointers.
I understand that i need to malloc memory for neighbor_address[0] and neighbor_address[1] to store their IP addresses. Since the IP address is of form "x.y.z.w" i will be doing a malloc of 7*sizeof (char).
My doubt is how much memory should i allocate for the base char **neighbor_address. Should it be 4 bytes so that it can store the IP address of the base pointer of neighbor_address[0]?
I say this because i get a SIGSEGV (Segmentation fault) if i don't do a malloc as follows:
neighbor_address = malloc (1, sizeof (char *));
Anything that i am missing?
You should not do malloc like this-
neighbor_address = malloc (1, sizeof (char *));
you are not following the syntax of malloc here. It is the syntax of calloc. If you are using calloc you can use this method-
neighbor_address = calloc (n, sizeof (char *));
If you want to use malloc Try the following changes-
neighbor_address = (char **)malloc (n * sizeof (char *));
for(i=0;i<n;i++)
neighbor_address[i] = (char *)malloc (8 * sizeof (char));
But You are using structure here. So you need to use arrow operator to allocate memory for char **neighbor_address; because it is a pointer type. Try this-
neighbors -> neighbor_address = (char **)malloc (n * sizeof (char *)); // n -> no of ip addresses
for(i=0;i<n;i++)
neighbors -> neighbor_address[i] = (char *)malloc (8 * sizeof (char));
Oh, I think you didn't understand the max length of an IP Address.
It could be 3 digits between every dot so it can be 255.255.255.255 at maximum.
So the code to dynamically allocate memory for it would be so:
#define MAX_IP strlen("255.255.255.255")
int i;
neighbors my_neighbors;
my_neighbors.num_neighbors = ?; //Some value that is the num of IP Addresses needed to be stored.
my_neighbors.neighbor_address = malloc(sizeof(char*)*my_neighbors.num_neighbors); //allocate a char* (that is about to be a string) for each neighbor.
for(i = 0 ; i < my_neighbors.num_neighbors ; i++)
{
my_neighbors.neighbor_address[i] = malloc(sizeof(char)*(MAX_IP+1)); //Allocating enough room in each IP string for 255.255.255.255 + '\0' (null).
}
//Doing some stuff.
//Freeing memory:
for(i = 0 ; i < my_neighbors.num_neighbors ; i++)
{
free(my_neighbors.neighbor_address[i]);
}
free(my_neighbors.neighbor_address);
And that's it.
Hope you understood.
You can allocate the memory like this.
neighbor_address = (char**)malloc(num_neighbors * sizeof(char*));
for(i=0; i<num_neighbors; ++i) {
neighbor_address[i] = (char*)malloc(len_of_address);
}
Make sure that 'len_of_address' is large enough to store all characters (including the terminating '\0' character if you plan to store \0-terminated strings).
Be aware of the fact that you need more space than 1 character per fragment of the ip address if it is a number larger than 9.
So to store 196.168.0.3 you would need at least 12 characters.
First, two things: sizeof(char) is 1, regardless of the implementation. And I think you misunderstood malloc prototype. It takes the number of bytes you want to allocate, and it returns the allocated pointer.
If you want to store x IPs, then you'll have to do:
neighbor_address = malloc(x * sizeof(char*));
And then if you want to store 7 chars in each string, you'll have to do:
for (i = 0; i < x; i++)
neighbor_adress[i] = malloc(7 + 1); // 7 chars plus '\0' character
You must allocate memory for an array of num_neighbors char pointers. But most of all, remember to # include <stdlib.h> : you called malloc with wrong parameters, and that's probably what caused the segfault before a wrong size.
The least error-prone pattern for using malloc is this one :
neighbor_address = malloc(num_neighbors * sizeof *neighbor_address);
Just put the same variable as left operand of = and operand of sizeof, and adjust the number of elements.

How to allocate memory for an arbitrary-sized array of fixed-length C strings

I am trying to allocate memory for an array of C strings. I can guarantee that the strings fit within MAX_STRING_LENGTH characters, but I don't know at compile time how many strings will be in the array (this is computed dynamically). When I use the code...
char *strings[MAX_STRING_LENGTH] = malloc( sizeof(char *) * numstrings );
...the compiler complains that this is an invalid initializer. When I use the code...
char strings[MAX_STRING_LENGTH][] = malloc( sizeof(char *) * numstrings );
...the compiler complains about an incomplete element type. What am I doing wrong here, and how can I allocate memory for this array?
char (*strings)[MAX_STRING_LENGTH] = malloc(sizeof *strings * num_strings);
will allocate a num_strings x MAX_STRING_LENGTH array of char as a contiguous chunk so that you don't have to do multiple levels of allocation.
strcpy(strings[i], "This is a test");
printf("%s\n", strings[j]);
etc. When you're done you only have to free(strings);.
The main drawbacks with this method are that you may not have enough memory to satisfy the request if num_strings is very large, and that you'll have some internal fragmentation if most of your strings are shorter than MAX_STRING_LENGTH.
With this declaration:
char *strings[MAX_STRING_LENGTH] = malloc(sizeof(char *) * numstrings);
It reads as if you're defining an array of C strings, whose count - not the individual string lengths - is MAX_STRING_LENGTH.
Better to define a **char, like so:
char **strings = malloc(sizeof(char *) * numstrings);
Later in your code, when you're ready to add a string to e.g. slot 5:
strings[5] = malloc(sizeof(char) * MAX_STRING_LENGTH));
or in an init loop such as:
for (i = 0; i < numstrings; i++)
strings[i] = malloc(sizeof(char) * MAX_STRING_LENGTH);
And, if at some point you need room for more strings, use realloc to grow the initial memory allocation.
char **strings;
strings=(char **) malloc(number of strings);
strings[i]=(char *) malloc(MAX_STRING_LENGTH);
If it is truly dynamic, then it may need to be something like this:
char **strings = malloc( sizeof(char*) * numstrings );
for ( int i = 0; i < numstrings; i++ )
strings[i] = malloc( MAX_STRING_LENGTH );
It is also possible to allocate it all in one chunk (makes freeing it easier) and then assign the individual pointers in the array to computed positions in the allocated buffer. That, though, adds some complexity that may not exceed the benefit.

How do I allocate memory for a pointer to an array of char *?

Could someone please explain how to correctly allocate memory for for a pointer to an array of pointer of characters in c? For example:
char *(*t)[];
I try to do it like this:
*t = malloc( 5 * sizeof(char*));
This gives me a compile error:
error: invalid use of array with unspecified bounds
Any assistance on this would be great! Thanks
What you can do is:
char **t = (char**)malloc( <no of elements> * sizeof(char*));
That allocates the array of pointers.
for (i = 0 ; i< <no of elements> ; i++)
{
t[i] = (char*)malloc( <length of text> * sizeof(char));
}
That allocates memory for the text that each element of the array points to.
When people say "a pointer to an array of X", usually they really mean a pointer to the first element of an array of X. Pointer-to-array types are very clunky to use in C, and usually only come up in multi-dimensional array usage.
With that said, the type you want is simply char **:
char **t = malloc(num_elems * sizeof *t);
Using a pointer-to-array type, it would look like:
char *(*t)[num_elems] = malloc(sizeof *t);
Note that this will be a C99 variable-length array type unless num_elems is an integer constant expression in the formal sense of the term.
Well it depends how you want it to be allocated, but here is one way.
char** myPointer = malloc(sizeof(char *) * number_Of_char_pointers)
int i;
for(i = 0; i < number_Of_char_pointers; i++)
{
myPointer[i] = malloc(sizeof(char) * number_of_chars);
}
something to note is that myPointer[i] is almost exactly identical to saying *(myPointer + i), when being used to dereference a variable, not during initialization.
Try this:
int main()
{
char** a = new char* [100];
delete []a;
return 0;
}

Another dynamic memory allocation bug

I'm trying to allocate memory for a multidimensional array (8 rows, 3 columns).
Here's the code for the allocation (I'm sure the error is clear for you)
char **ptr = (char **) malloc( sizeof(char) * 8);
for (i = 0; i < 3; i++)
ptr[i] = (char *) malloc( sizeof(char) * 3);
The crash happens when I reference this:
ptr[3][0];
Unhandled exception at 0x0135144d in
xxxx.exe:
0xC0000005: Access violation writing
location 0xabababab.
Are there any recommended references/readings for this kind of subject?
Thanks.
The first malloc() is wrong. It should be:
malloc(sizeof(char*) * 8)
A char* is 4 byte (or 8 byte... see P.S) whereas char is 1 byte. When you write ptr[3] the compiler will assume that you want to access to the base address of ptr + 3*sizeof(char*). So you will access to memory that you didn't allocate.
P.S:
To be more precise, char* is 4 byte on 32 bit systems and 8 byte on 64 bit systems.
I don't know offhand any books on memory allocation, but any introductory C tutorial should explain it. As for your bug, your for loop only initializes the first 3 rows, instead of the 8 you allocated. It should be:
for (i = 0; i < 8; i++)
char **ptr = (char **) malloc( sizeof(char *) * 8);
Before, you were allocating space for 8 chars. You want space for 8 pointers to char.
Michael pointed out the other error, writing the first char from a string you never allocated.
It may help if you use constants, like:
const int STRING_COUNT = 8;
const int STRING_LEN = 2;
char **ptr = (char **) malloc( sizeof(char *) * STRING_COUNT);
ptr is an array of 8 pointers, not chars, so the first line should be:
char **ptr = (char **) malloc( sizeof(char*) * 8)
Because there are 8 pointers, the loop should go from 0 to 7:
for (i = 0; i < 8; i++)
You can also consider using a less prone to errors version of the first line:
char **ptr = (char **) malloc( sizeof(*ptr) * 8)
And the last one:
ptr[i] = (char *) malloc( sizeof(*ptr[i]) * 3);
The rule is: always take sizeof of dereferenced lvalue. If lvalue is ptr, then you need sizeof(*ptr). ptr[i] becomes sizeof(*ptr[i]).
There are several errors/inconsistencies in your code, but the first major one is the wrong sizeof in the first allocation. The error that you made could have easily been avoided if you followed some good-practice guidelines:
(1) As much as possible avoid using type names in statements. Type names belong in declarations, not in statements.
(2) Don't cast the result of memory allocation functions.
The first allocation should have looked as follows
char **ptr = malloc( 8 * sizeof *ptr );
Try to remember this as a generic pattern: malloc requestes should normally look as follows
pointer = malloc( count * sizeof *pointer );
Note: no type names are mentioned in the above statement.
Of course, you should also make up your mind about the first size of your 2D array. You attempt to allocate 8, then you only initialize 3. Why?
There are two problems.
First, as others have pointed out, your initial malloc should be
malloc(sizeof(char *) * 8)
Second, you are initializing the first three elements in the 8-element array, but ptr[3][0] refers to the fourth element. Thus the crash.

Resources