I have encountered so called cryptic realloc invalid next size error , I am using gcc on linux my code is
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int i;
char *buf;
char loc[120];
buf = malloc(1);
int size;
for(i=0;i<1920;i++)
{
sprintf(loc,"{Fill_next_token = my_next_token%d; Fill_next_token_id = my_next_token_id = my_next_token_id%d}",i,i);
size = strlen(buf)+strlen(loc);
printf("----%d\n",size);
if(!realloc(buf,size))
exit(1);
strcat(buf,loc);
}
}
(mine might be duplicate question) here the solution somewhere lies by avoiding strcat and to use memcpy , But in my case I really want to concatenate the string . Above code works for good for such 920 iterations but in case 1920 realloc gives invalid new size error. Please help to find alternative of concatenating , looking forward to be a helpful question for lazy programmers like me .
Your code has several issues:
You are not accounting for null terminator when deciding on the new length - it should be size = strlen(buf)+strlen(loc)+1;
You are ignoring the result of realloc - you need to check it for zero, and then assign it back to buf
You do not initialize buf to an empty string - this would make the first call of strlen produce undefined behavior (i.e. you need to add *buf = '\0';)
Once you fix these mistakes, your code should run correctly:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main() {
int i;
char *buf= malloc(1);
*buf='\0';
char loc[120];
for(i=0;i<1920;i++) {
sprintf(loc,"{Fill_next_token = my_next_token%d; Fill_next_token_id = my_next_token_id = my_next_token_id%d}",i,i);
int size = strlen(buf)+strlen(loc)+1;
printf("----%d\n",size);
char *tmp = realloc(buf,size);
if(!tmp) exit(1);
buf = tmp;
strcat(buf, loc);
}
}
Demo.
buf is not a valid string so strcat() will fail since it expects a \0 terminated string.
If you want to realloc() buf then you should assign the return value of realloc() to buf which you are not doing.
char *temp = realloc(buf,size+1);
if(temp != NULL)
buf = temp;
Point 1. Always use the return value of realloc() to access the newly allocated memory.
Point 2. strcat() needs a null-terminating string. Check the first iteration case.
Related
First of all Thanks for visiting my question... :)
I am interested in competitive programming, so I daily do some amount of problem-solving, however, I only know C language at a decent level, and I often face problems while dynamically allocating something as usual, especially for strings and 2D arrays.
But I somehow manage to find ways (thanks to StackOverflow), for example, I wanted to create a function that scans string dynamically until the user enters space or new line, so I came up with the solution below and it works perfectly:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// scanf("%[^\n]%*c", str);
char *create_string(char *ptr)
{
ptr = (char *)malloc(0 * sizeof(char));
unsigned int size = 0;
char c = 0;
while (1)
{
scanf("%c", &c);
if (c == 32 || c == 10)
{
break;
}
size++;
ptr = (char *)realloc(ptr, size * sizeof(char));
ptr[size - 1] = c;
}
ptr = (char *)realloc(ptr, (size + 1) * sizeof(char));
ptr[size] = '\0';
return ptr;
}
int main()
{
char *str;
str = create_string(str);
printf("%s", str);
printf("\n%lu", strlen(str));
return 0;
}
And now for curiosity purposes, I want to know how can I do this same thing using the void function?, something like:
char *str;
create_string(&str);
should start storing everything in the dynamic memory which is pointed by str.
Also, please if you have more knowledge to show in DMA for 2D array, then please show me it, feel free to give examples with different problems.
And also How can I stop scanning the string (which was allocated dynamically) with specific string ending? for example, scanning(any kind of scanning, i.e. int, bool, custom structures etc...) should stop if user enters string "STOP", Please feel free to give pictorial examples.
Because I am sure that this question is burning like a fire in beginner's and intermediate C programmers' minds.
As C passes arguments by value, to return something via an out parameter, you need to pass in a pointer to it. So to return a char * it would:
void create_string(char **s) {
*s = malloc(42);
}
Here is your refactored code. I changed the following:
Eliminate return value of update caller.
Initialize *ptr = malloc(1) for the trailing '\0'. It eliminates an unnecessary and implementation defined malloc(0). This also eliminates the (*ptr)[size] = ... which looks wrong as the last index is expected to be size - 1. Alternatively initialize it to NULL.
Use character constants instead of magic values (32, 10).
sizeof(char) is defined as 1 so leave it out.
Reduced scope of variable c.
free() memory allocated.
(cosmetic) Use size_t size instead of unsigned int size.
(cosmetic) Avoid the noise of casting casting void *.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void create_string(char **ptr) {
*ptr = malloc(1);
size_t size = 1;
for(;;) {
char c;
scanf("%c", &c);
if (c == ' ' || c == '\n') break;
(*ptr)[size-1] = c;
size++;
*ptr = realloc(*ptr, size);
}
(*ptr)[size-1] = '\0';
}
int main() {
char *str;
create_string(&str);
printf("%s\n", str);
printf("%zu\n", strlen(str));
free(str);
}
I didn't fix these issue:
Check return value of malloc(), realloc().
v = realloc(v, ...) is unsafe and will leak memory if realloc() fails. You need to do char *tmp = realloc(v,...); if(!tmp) { // err }; v = tmp;.
Check return value of scanf() otherwise you may be operating on uninitialized data.
Use scanf("%s", ..) instead of for(;;) { scanf("%c", ...). It's more efficient to allocate a chunk at a time instead of per byte.
If user enters ctrl-d (EOF) the program will go into an infinite loop.
It's good idea to separate i/o from logic (i.e. let caller do the scanf(). That way create_string() is much more reusable.
Hi I wrote this code and it worked but in the end, "the program has stopped working"
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
void main()
{
char *s;
s=(char*)malloc(sizeof(char));
printf("Enter a string:\n");
gets(s);
while (*s)
{
if (*s>= 65 && *s<=90)
printf("%c",*s+32);
else if(*s>=97 && *s<=122)
printf("%c",*s-32);
else
printf("%c",*s);
*s++;
}
free(s);
}
That code does not work, in fact it has undefined behavior.
This:
s = (char *) malloc(sizeof(char));
allocates 1 byte of storage, into which you then scan a string, thus very likely leading to buffer overflow. The buffer can only hold a single string, i.e. string of 0 characters before the terminator character at the end.
You meant:
s = malloc(128);
or something like that.
There's no need to cast, and sizeof (char) is always 1 so that doesn't add anything.
Also, as more of a code review, magic numbers in code is generally considered a bad idea, instead write:
if (*s >= 'A' && *s <= 'Z')
or even better
if (isupper((unsigned int) *s))
to not hard-code a depdency on ASCII.
UPDATE Oh, and as pointed out in a comment, you can't change the value of s and then pass the changed value to free(), that is undefined behavior also. The address passed to free() must be the same as the one you got back from malloc().
Use a separate variable for the iteration:
char *p = s;
and only free() the original s.
Firstly, by s=(char*)malloc(sizeof(char)); you are allocating only 1 byte of memory for buffer. Allocate enough memory to store the input. Also avoid typecasting malloc() result. Better version looks like
s = malloc(MAX * sizeof(*s));/* MAX is num of bytes you need to define */
Secondly don't use gets() use fgets() instead. Read man 3 gets or check https://linux.die.net/man/3/gets
Finally use int main(void) { } instead of just main(){ }
And more importately when you do free(s) at that time s doesn't point to memory which was earlier allocated to it because of s++ so it may result error like
free(): invalid pointer:
So don't change s use s[row] while iterating OR you can assign s to other pointer and then you can do free(s).
Complete code
int main() {
char *s = NULL;
int size = MAX*sizeof(*s);/*define MAX value, it is no of bytes need*/
s = malloc(size);/* this is generic
sizeof(*s) works for any data type */
printf("Enter a string:\n");
fgets(s,size,stdin);/* use fgets() instead of gets() */
int row = 0;
while (s[row]!='\0') {
if ( *(s+row) >= 65 && *(s+row) <= 90)
printf("%c",*(s+row) + 32);
else if( *(s+row) >=97 && *(s+row) <= 122)
printf("%c",*(s+row) - 32);
else
printf("%c",*(s+row));
row++;
}
free(s);/* s still points to same location */
return 0;
}
Also you can use isupper() instead of comparing each char ASCII value.
This is wrong.
s = (char*)malloc(sizeof(char));
printf("Enter a string:\n");
gets(s);
s = (char*)malloc(sizeof(char)); allocates 1 byte of memory. And then with
gets(s); you get a string, which will be Undefined Behavior.
You have to changed it to
s = malloc(MAX_LENGTH * sizeof(char)); //MAX_LENGTH is user defined
Additionally, you must check if malloc() returned anything. If it returns NULL then it means no memory is allocated and all of the existing program will invoke undefined behavior.
Also, there is no need to cast the malloc result, so to further improve your code, you need to change it to,
s = malloc(MAX_LENGTH * sizeof(char));
if(s == NULL)
{
// Add error handling here
}
Also,
void main()
isn't by the standard anymore, see This post which explains why. If you want to know what C11 standard states about it, then refer the standard here: Section 5.1.2.2.1 Program startup
So change it to,
int main(void)
You should make sure that you call free(s); only if it was allocated. As one of the comments below rightly indicates that free(NULL); is NOT a problem, but it also have no effect, so why call it anyway.
Make s point to NULL again, but its irrelevant in this piece of code.
So I'm working through "Sams Teach Yourself C Programming in One Hour a Day, Seventh Edition" Lesson 10 Exercise 7 which asks to "Write a function that accepts two strings. Use the malloc() function to allocate enough memory to hold the two strings after they have been concatenated (linked). Return a pointer to this new string."
I am sure there are much more elegant ways to go about this than what I have attempted below. I am mostly interested in why my solution doesn't work. I have only been learning C for a few months and have no significant programming background. Please let me know why this crashes on compilation. I am using Code Blocks on Win 7 with GNU GCC Compiler if that makes a difference. Thank you :)
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
int ctr;
int ctr2;
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
Thank you for the help. After reviewing everyone's feedback on my errors I revised the code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenated(char array1[], char array2[]);
int main(void)
{
char *array1 = "Testing Testing One Two ";
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
array3 = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) );
strcat(array3, array1);
strcat(array3, array2);
return array3;
}
If anyone sees any redundancies/unnecessary remaining code the could/should be deleted, please let me know. I recognize the benefit of being as concise as possible.
Your code has a bunch of issues:
int ctrtotal is never initialized, so you are mallocing 0 bytes
concatenated() is copying characters to an uninitialized array3. This pointer should point to a mallocd buffer.
If concatenated is allocating the memory, then main doesn't need to. Instead it should use the result of concatenated.
I don't want to give you the full code, and let you to miss out on this learning opportunity. So concatenated should look like this, in psuedo-code:
count = length_of(string1) + length_of(string2) + 1
buffer = malloc(count)
copy string1 to buffer
copy string2 to buffer, after string1
set the last byte of buffer to '\0' (NUL)
return buffer
In C, strings are represented as a NUL-terminated array of characters. That's why we allocate one additional byte, and terminate it with \0.
As a side-note, when dealing with strings, it is far easier to work with pointers, instead of treating them as arrays and accessing them via indices.
There's a lot of code here that just doesn't make any sense. I suggest that you first write this program on paper. Then, "execute" the program in your head, stepping through every line. If you get to something you don't understand, then you need to either fix your understanding, or your incorrect code. Don't try to write code that looks like some other bit of code.
There's also a library function called strcat which will make this task even easier. See if you can figure out how to use it here.
Spoiler --> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concatenate2(const char* s1, const char* s2);
int main(void)
{
char *comboString;
char *array1 = "You're the man ";
char *array2 = "Now Dog!";
comboString = concatenate2(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char *concatenate2(const char* s1, const char* s2)
{
char *result;
result = malloc(strlen(s1) + strlen(s2) + 1);
*result = '\0';
strcat(result, s1);
strcat(result, s2);
return result;
}
You forgot to allocate memory for third, concatenated, array of chars (in function)
You should do something like this:
char *array3;
array3 = (char *)malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) ); // +1 for '\0' character.
and then write chars from first and second array into third.
Perhaps a stroll through the question code is best.
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
Notice that the above line declares ctrtotal to be an integer, but does not specify the value of the integer.
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
Notice that the above line allocates memory and sets 'comboString' to point at that memory. However, how much memory is being allocated?
(ctrtotal[???] * sizeof(char)[1])
What is the value of (??? * 1) ? This is a problem.
concatenated(array1, array2);
The intent of the line above is that array1["You\'re the man "] and array2["Now Dog!"] will be joined to form a new string["You\'re the man Now Dog!"], which will be placed in allocated memory and returned to the caller.
Unfortunately, the returned memory containing the string is not captured here. For example, perhaps the above line should be:
comboString = concatenated(array1, array2);
While this make sense, for this line, it begs a question of the purpose of the lines:
comboString = (char *)malloc(ctrtotal * sizeof(char));
as well as the global variable:
int ctrtotal;
and the later reference:
ctrtotal = (ctr2 + ctr + 2);
Perhaps all of these 3 lines should be deleted?
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
Notice that '*array3' is now a defined pointer, but it is not pointing anywhere specific.
int ctr;
int ctr2;
The purpose of 'concatenated()' is to join array1 and array1 into allocated array3. Unfortunately, no memory is allocated to array3.
Below, the memory where array3 is pointing will be modified. Since array3 is not pointing anywhere specific, this is not safe.
Prior to modifying memory where array 3 is pointing, it is important to point array3 at memory where it is safe to modify bytes. I suggest that the following code be inserted here:
array3 = malloc(strlen(array1) + strlen(array2) + 1);
Now, array3 points to allocated memory, large enough to hold both strings plus the string termination character '\0'.
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
I am responding to your revised code. There are a few bugs in it.
...
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
...
The malloc is unnecessary here and actually a bug in your code. You are allocating a block of memory, but you then replace the value of the pointer comboString with the pointer from the call to concatenated. You lose the pointer to the block of memory allocated in main and thus never are able to free it. Although this will not be a problem in the code you have right now since main returns soon after, it could cause a memory leak in an application that ran for a longer time.
strcat(array3, array1);
This is also a bug. strcat is going to walk through array3 to find '\0' and then once it is found copy in array1 from that index on, replacing the '\0'. This works fine here since the memory block that was allocated for array3 is going to be zeroed out** as no block has yet been freed by your program. However, in a longer running program you can end up with a block that does not start with a '\0'. You might end up corrupting your heap, getting a segfault, etc.
To fix this, you should use strcpy instead, array3[0] = '\0', or *array3 = '\0'
** When the operating system starts your program it will initialize the memory segment it reserves for it with zeroes (this actually isn't a necessity but will be true on almost any operating system). As your program allocates and frees memory, you will eventually wind up with values that are not zero. Note that the same bug can occur with uninitialized local variables such as:
int i;
for (; i < 10; i++);
This loop will run 10 times whenever the space on the runtime stack where i is stored is already 0.
Overall, the takeaway is to be very careful with arrays and dynamic memory allocation in C. C offers you none of the protections that modern languages do. You are responsible for making sure you stay within the bounds of your array, initialize your variables, and properly allocate and free your memory. Neglecting these things will lead to obscure bugs that will take you hours to find, and most of the times these bugs will not appear right away.
I have a character pointer, which has a string assigned to it. And I'm sure that the string is of 8 characters length. (Ex: SHIVA0BS) And it is also a fact that the last two letters are always going to be "BS". But I'm just going to double check it. Now I'd like to take the first 6 characters ("SHIVA0") and append it to something else, say ("SHIVA0NN") - how would I make it possible?
#include<stdio.h>
#include<stdlib.h>
void main()
{
char *ptr, *new;
ptr = "FECI00BS";
strncpy(new,ptr,6);
printf("%s",new);
strcat(new,"NN");
}
The above code is what I wrote. And I'm not sure why it is not working. I understand that my requirement is very trivial, but I tried printfs in between. I was able to find that (ptr+6) printed "BS", so that 6 is the length that I need. But this is still not working. Any help appreciated. I need the output in a string pointer. A new one is fine. But a string pointer.
P.S: Only C code please. No C++.
You didn't allocate memory to hold your new string
char * new = calloc(1, 10); // on heap
or
char new[10]; // on stack
memset(new, 0, sizeof(new)); // zero it
You're not allocating memory for storing the strings.
You need to allocate memory for both *ptr and *new.
The bare minimum would be:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
char *ptr, *new;
new = (char*)malloc(sizeof(char) * 9);
new = (char*)malloc(sizeof(char) * 9);
ptr = "FECI00BS";
strncpy(a,ptr,6);
printf("%s",new);
strcat(a,"NN");
printf("%s",new);
}
You need 9 bytes (assuming your platform needs one byte per char) because of the End-Of-Line character, '\0', that needs to be present at the end of strings in order to use some string.h functions or print them correctly.
Also, read on why you need to be careful with strncpy. Depending on your platform, you may have access to some newer, safer alternatives from the C standard.
I think you want:
sprintf(ptr+6, "NN");
That will modify your buffer to convert BS into NN. In this case you can get rid of the new variable.
EDIT
Try this. Notice the char ptr[] instead of char* ptr. By using [] instead of a pointer you are allocating the buffer on the stack. This allows you to write to the buffer.
#include<stdio.h>
#include<stdlib.h>
void main()
{
char ptr[] = "FECI00BS";
sprintf(ptr+6,"NN");
printf(ptr);
}
Just a few simple checks and memcpy().
char *ShivaAppend(char *dest, const char *ptr, const char *suffix) {
size_t len = strlen(ptr);
if (len != 8) {
return NULL;
}
if (strcmp(ptr, "BS") != 0) {
return NULL;
}
len = strlen(suffix);
if (len != 2) {
return NULL;
}
memcpy(dest, ptr, 6);
memcpy(&dest[6], suffix, 2);
return dest;
}
...
char dest[9];
char *p = ShivaAppend(dest, "SHIVA0BS", "NN")
puts(p == NULL ? "fail", p);
I have a program that accepts a char input using argv from the command line. I copy the input argv[1] using strcpy to a pointer called structptr(it goes to structptr->words from struct) where memory has been allocated. I then copy character by character from the memory that the pointer structptr points to another pointer called words that points to memory that has been allocated. After i've copied one character i print that element [c] to make sure that it has been copied correctly(which it has). I then finish copying all of the characters and return the result to a char pointer but for some reason it is blank/null. After each copying of the characters i checked if the previous elements were correct but they don't show up anymore([c-2], [c-1], [c]). Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct StructHolder {
char *words;
};
typedef struct StructHolder Holder;
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
int main(int argc, char **argv){
Holder *structptr=malloc(sizeof(Holder));
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
char *charptr;
charptr=(GetCharacters(structptr));
printf("%s\n", charptr);
return 0;
At first I thought this was the problem:
char *words=malloc(sizeof(char)) is allocating 1 byte (sizeof 1 char). You probably meant char *words = malloc(strlen(ptr->words)+1); - You probably want to null check the ptr and it's member just to be safe.
Then I saw the realloc. Your realloc is always 1 char short. When i = 0 you allocate 1 byte then hit the loop, increment i and put a char 1 past the end of the realloced array (at index 1)
Also your strcpy in main is has not allocated any memory in the holder.
In these two lines,
structptr->words=malloc(strlen(argv[1]));
strcpy(structptr->words, argv[1]);
need to add one to the size to hold the nul-terminator. strlen(argv[1]) should be strlen(argv[1])+1.
I think the same thing is happening in the loop, and it should be larger by 1. And sizeof(char) is always 1 by definition, so:
...
words=realloc(words,i+2);
}
words=realloc(words,i+2); // one more time to make room for the '\0'
words[strlen(ptr->words)]='\0';
FYI: Your description talks about structptr but your code uses struct StructHolder and Holder.
This code is a disaster:
char *GetCharacters(Holder *ptr){
int i=0;
char *words=malloc(sizeof(char));
for(i;i<strlen(ptr->words);i++){
words[i]=ptr->words[i];
words=realloc(words,sizeof(char)+i);
}
words[strlen(ptr->words)]='\0';
return words;
}
It should be:
char *GetCharacters(const Holder *ptr)
{
char *words = malloc(strlen(ptr->words) + 1);
if (words != 0)
strcpy(words, ptr->words);
return words;
}
Or even:
char *GetCharacters(const Holder *ptr)
{
return strdup(ptr->words);
}
And all of those accept that passing the structure type makes sense; there's no obvious reason why you don't just pass the const char *words instead.
Dissecting the 'disaster' (and ignoring the argument type):
char *GetCharacters(Holder *ptr){
int i=0;
OK so far, though you're not going to change the structure so it could be a const Holder *ptr argument.
char *words=malloc(sizeof(char));
Allocating one byte is expensive — more costly than calling strlen(). This is not a good start, though of itself, it is not wrong. You do not, however, check that the memory allocation succeeded. That is a mistake.
for(i;i<strlen(ptr->words);i++){
The i; first term is plain weird. You could write for (i = 0; ... (and possibly omit the initializer in the definition of i, or you could write for (int i = 0; ....
Using strlen() repeatedly in a loop like that is bad news too. You should be using:
int len = strlen(ptr->words);
for (i = 0; i < len; i++)
Next:
words[i]=ptr->words[i];
This assignment is not a problem.
words=realloc(words,sizeof(char)+i);
This realloc() assignment is a problem. If you get back a null pointer, you've lost the only reference to the previously allocated memory. You need, therefore, to save the return value separately, test it, and only assign if successful:
void *space = realloc(words, i + 2); // When i = 0, allocate 2 bytes.
if (space == 0)
break;
words = space;
This would be better/safer. It isn't completely clean; it might be better to replace break; with { free(words); return 0; } to do an early exit. But this whole business of allocating one byte at a time is not the right way to do it. You should work out how much space to allocate, then allocate it all at once.
}
words[strlen(ptr->words)]='\0';
You could avoid recalculating the length by using i instead of strlen(ptr->words). This would have the side benefit of being correct if the if (space == 0) break; was executed.
return words;
}
The rest of this function is OK.
I haven't spent time analyzing main(); it is not, however, problem-free.