Using fgets() with char* type - c

I have a simple question about using fgets() with char* string.
....
char *temp;
FILE fp=fopen("test.txt", "r");
fgets(temp, 500, fp);
printf("%s", temp);
....
This code didn't work well.
But after I modified char *temp to char temp[100];, the code worked well as I intended.
What is the difference between those two?
When I googled it, some said that memory must be allocated to char * using malloc()...
But I couldn't understand it.

char *temp is only a pointer. At begin it doesn't points to anything, possibly it has a random value.
fgets() reads 500 bytes from fp to the memory addresse, where this temp pointer points! So, it can overwrite things, it can make segmentation faults, and only with a very low chance will be work relativale normally.
But char temp[500] is a 500 bytes long array. That means, that the compiler does the allocation on the beginning of your process (or at the calling of your function). Thus this 500 bytes will be a useable 500 bytes, but it has a price: you can't reallocate, resize, free, etc. this.
What the google wants from you, is this:
char *temp = (char*)malloc(500);
And a
free(temp);
after you don't need this any more.

When we write
char *temp ;
it means temp is an uninitialized pointer to char i.e. currently it does not contain any address in it .
While using fgets you have to pass a string in which the bytes read from file pointer is to be copied . link
since the temp is uninitialized , the fgets looks like this
fgets(<no string> , 500 , fp ) ;
which is invalid .
Hence , we should give initialized string which can be formed as :
1) char *temp = malloc(sizeof(500)) ;
or
2) char temp[500] ;
Hence if we pass initialized string to fgets , it would look like
fgets( < some string > , 500 , fp) ;

char *temp is uninitialized, that is, it isn't pointing to valid memory. Either make it an array (char temp[]) or use malloc to assign memory for it.

Related

How to fix "realloc(): invalid pointer"

I am trying to write a function to convert a text file into a CSV file.
The input file has 3 lines with space-delimited entries. I have to find a way to read a line into a string and transform the three lines from the input file to three columns in a CSV file.
The files look like this :
Jake Ali Maria
24 23 43
Montreal Johannesburg Sydney
And I have to transform it into something like this:
Jake, 24, Montreal
...etc
I figured I could create a char **line variable that would hold three references to three separate char arrays, one for each of the three lines of the input file. I.e., my goal is to have *(line+i) store the i+1'th line of the file.
I wanted to avoid hardcoding char array sizes, such as
char line1 [999];
fgets(line1, 999, file);
so I wrote a while loop to fgets pieces of a line into a small buffer array of predetermined size, and then strcat and realloc memory as necessary to store the line as a string, with *(line+i) as as pointer to the string, where i is 0 for the first line, 1 for the second, etc.
Here is the problematic code:
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#define CHUNK 10
char** getLines (const char * filename){
FILE *file = fopen(filename, "rt");
char **lines = (char ** ) calloc(3, sizeof(char*));
char buffer[CHUNK];
for(int i = 0; i < 3; i++){
int lineLength = 0;
int bufferLength = 0;
*(lines+i) = NULL;
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lineLength += buffLength;
*(lines+i) = (char*) realloc(*(lines+i), (lineLength +1)*sizeof(char));
strcat(*(lines+i), buffer);
}while(bufferLength ==CHUNK-1);
}
puts(*(lines+0));
puts(*(lines+1));
puts(*(lines+2));
fclose(file);
}
void load_and_convert(const char* filename){
char ** lines = getLines(filename);
}
int main(){
const char* filename = "demo.txt";
load_and_convert(filename);
}
This works as expected only for i=0. However, going through this with GDB, I see that I get a realloc(): invalid pointer error. The buffer loads fine, and it only crashes when I call 'realloc' in the for loop for i=1, when I get to the second line.
I managed to store the strings like I wanted in a small example I did to try to see what was going on, but the inputs were all on the same line. Maybe this has to do with fgets reading from a new line?
I would really appreciate some help with this, I've been stuck all day.
Thanks a lot!
***edit
I tried as suggested to use calloc instead of malloc to initialize the variable **lines, but I still have the same issue.I have added the modifications to the original code I uploaded.
***edit
After deleting the file and recompiling, the above now seems to work. Thank you to everyone for helping me out!
You allocate line (which is a misnomer since it's not a single line), which is a pointer to three char*s. You never initialize the contents of line (that is, you never make any of those three char*s point anywhere). Consequently, when you do realloc(*(line + i), ...), the first argument is uninitialized garbage.
To use realloc to do an initial memory allocation, its first argument must be a null pointer. You should explicitly initialize each element of line to NULL first.
Additionally, *(line+i) = (char *)realloc(*(line+i), ...) is still bad because if realloc fails to allocate memory, it will return a null pointer, clobber *(line + i), and leak the old pointer. You instead should split it into separate steps:
char* p = realloc(line[i], ...);
if (p == null) {
// Handle failure somehow.
exit(1);
}
line[i] = p;
A few more notes:
In C, you should avoid casting the result of malloc/realloc/calloc. It's not necessary since C allows implicit conversion from void* to other pointer types, and the explicit could mask an error where you accidentally omit #include <stdlib.h>.
sizeof(char) is, by definition, 1 byte.
When you're allocating memory, it's safer to get into a habit of using T* p = malloc(n * sizeof *p); instead of T* p = malloc(n * sizeof (T));. That way if the type of p ever changes, you won't silently be allocating the wrong amount of memory if you neglect to update the malloc (or realloc or calloc) call.
Here, you have to zero your array of pointers (for example by using calloc()),
char **line = (char**)malloc(sizeof(char*)*3); //allocate space for three char* pointers
otherwise the reallocs
*(line+i) = (char *)realloc(*(line+i), (inputLength+1)*sizeof(char)); //+1 for the empty character
use an uninitialized pointer, leading to undefined behaviour.
That it works with i=0 is pure coindicence and is a typical pitfall when encountering UB.
Furthermore, when using strcat(), you have to make sure that the first parameter is already a zero-terminated string! This is not the case here, since at the first iteration, realloc(NULL, ...); leaves you with an uninitialized buffer. This can lead to strcpy() writing past the end of your allocated buffer and lead to heap corruption. A possible fix is to use strcpy() instead of strcat() (this should even be more efficient here):
do{
fgets(buffer, CHUNK, file);
buffLength = strlen(buffer);
lines[i] = realloc(lines[i], (lineLength + buffLength + 1));
strcpy(lines[i]+lineLength, buffer);
lineLength += buffLength;
}while(bufferLength ==CHUNK-1);
The check bufferLength == CHUNK-1 will not do what you want if the line (including the newline) is exactly CHUNK-1 bytes long. A better check might be while (buffer[buffLength-1] != '\n').
Btw. line[i] is by far better readable than *(line+i) (which is semantically identical).

Unable to print a char* string

It's not clear to me what's wrong with my program, it's a simple code to open a file, read the first line from it, and then print it. But the program keeps crashing. The actual content of my text file is a sentence: Test my code.
int main(void)
{
FILE *stream;
char *s;
stream = fopen("input.txt", "r");
fscanf(stream, " %s", &s);
printf("%s", s);
fclose(stream);
return 0;
}
I'm instructed not to use the library functions found in <string.h>
s is an uninitialized pointer. You need to allocate some memory for fscanf to write into.
char *s;
Allocates the number of bytes needed for holding a memory address (on most systems 32/64 bits).
But since you are not initializing the pointer, its value (the address it points to) is undefined.
Ergo: fscanf tries to write to an undefined memory address.
I initialized it as char *s = NULL;
Yes, the pointer is now initialized (yay!) but now points to nowhere.
Ergo: fscanf will try to write to nothing.
The solution is to allocate some memory fscanf can use.
fscanf does not magically allocate memory for you!
You can use either stack memory or dynamic allocated memory (heap).
Stack memory is easier to manage but is much smaller than the heap.
Here a solution which uses memory on the stack:
// Allocates 10 bytes on the stack
// Given 1 Character = 1 Byte the
// buffer can hold up to 9 characters.
char myBuffer[10];
// Initialize s with the address of myBuffer
char *s = myBuffer;
// Call fscanf
fscanf(stream, "%9s", s);
You may be wondering why I used %9s instead of %s.
The reason is to prevent a buffer overflow:
fscanf does not know how big the buffer is, so you need to tell it.
Otherwise fscanf will write data beyond your allocated memory.
I suggest you read up on C strings and memory management in general.
There are few things you are missing in your code.
// Uninitialise pointer, you need to allocate memory dynamically with malloc before you use it. That is
char *s;
int size = 20; // size of the string you want
s = malloc(size * sizeof(char));
// Or you can use a VLA and with this you don't have to use free(s)
char s[20];
// fopen could fail, always check the return value before using it.
stream = fopen("input.txt", "r");
if(stream == NULL){
perror("File opening failed");
return EXIT_FAILURE;
}
fscanf(stream, "%s", s);
//Don't forget to do free(s) to free memory allocated with malloc . when you are done with it

fgets error and strings declaration style on c

I'm curious about one thing, the following code works perfectly.
#include <stdio.h>
int main()
{
FILE * fp = fopen("test.txt", "r");
char line[100];
while( fgets(line, sizeof(line), fp) != NULL )
fputs(line, stdout);
fclose(fp);
return 0;
}
But why it is not possible to use instead:
char *line;
Without causing fgets to crash?
fgets crashes because it is writing the result into unallocated memory.
Without any further memory allocation, char *line points to "nothing". It points to something, but not to any valid memory location -- null if your compiler sets uninitialized values to 0, or any random memory location anywhere on or not on your system.
Even if fgets does not crash, you cannot predict what it does as writing into unallocated memory results in undefined behavior (What is undefined behavior?).
It is possible. Just point it to some valid memory.
char line[100];
char* linep = line ;
while( fgets(linep, sizeof(line), fp) != NULL )...
If you don't assing line to linep, then linep points to random memory, and you cannot use that.
char *line and char line[100] don't mean the same.
The first is a pointer to a char, we don't know if it will be a single char or an array of chars it is pointing to. The second on the other hand is an array.
fgets needs a valid location to write to. In this case, char *line doesn't have any valid location to point at, whereas char line[100] is a valid char array location

C strings by reference voodoo

I am a novice programmer and I hagly appreciate any advice with my problem here.
I've made a procedure that gets a string in buffer and parses it in three cunks, separated by the first 2 ";".
What I tried to do is to pass 3 char pointers in where I will store my parsed string. But all I got in the calling function is memory garbage. What am I doing wrong?
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje){
char *temp;
temp=(char *)malloc(sizeof(buf));
strcpy(temp, buf);
printf("\ntemp adentro de la funcion = %s\n", temp);
idNodo = strtok (temp,";");
idMensaje = strtok (NULL, ";");
mensaje = strtok (NULL, "\0");
printf("\nADENTRO\nidNodo: %s\nidMensaje: %s\nmensaje: %s", idNodo, idMensaje, mensaje);
}
this function is called this way:
char *idnod=NULL;
char *idmen=NULL;
char *men=NULL;
idnod=(char *)malloc(sizeof(buffer));
idmen=(char *)malloc(sizeof(buffer));
men=(char *)malloc(sizeof(buffer));
parseomensaje (buffer, &idmen, &idnod, &men);
after parseomensaje is executed buffer contains its original string, but idmen, idnod and men are blank.
I was reading from tutorials that pointers names are pointers itself, so it is the same thing as passing a parameter by reference, but in case of a string I need to pass the pointer address to a pointer to pointer...
I was reading it from here, but I'm still trying to figure it out.
PD: I apologize for my English, please feel free to point any mistakes in my writing. :)
This is incorrect:
char *temp;
temp=(char *)malloc(sizeof(buf));
as the array will degrade to a char* within the function, so only sizeof(char*) bytes are being allocated (typically 4 or 8 bytes). If the actually length of buf is greater than 4 or 8 bytes then the program has undefined behaviour as the strcpy() will be writing beyond the bounds of the array. Basically:
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje){
is equivalent to:
void parseomensaje(char* buf, char **idNodo, char **idMensaje, char **mensaje){
If you are, as you say, a novice programmer I would recommend avoiding dynamic memory allocation until you get more comfortable with the language. Modify the program to use fixed sized arrays instead of dynamically allocated memory (and prevent writing beyond the bounds of the arrays). Once you have that working and fully understand it then attempt to use dynamically allocated memory.
First of all you have multiple memory leaks in your program. Consider freeing every single memory chunk you've allocated thanks to malloc once you don't need them anymore.
As regard your function:
void parseomensaje(char buf[256], char **idNodo, char **idMensaje, char **mensaje)
Why do you pass char** pointers on your function? Pass char* instead. Because strtok is declared this way:
char *strtok(char *str, const char *delim);
Moreover, you don't need to allocate any memory before calling parseomensaje since strtok returns a pointer on your own memory, not new allocated one.

segmentation fault during execution

#include<stdio.h>
int main()
{
char *arg[10],*c;
int count=0;
FILE *fp,*fq;
printf("Name of the file:");
scanf("%s",arg[1]);
fp=fopen(arg[1],"w");
printf("\t\t%s",arg[1]);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((*c=getchar())!=EOF)
{
fwrite(c,sizeof(char),1,fp);
count++;
}
return 0;
}
Change this line
char *arg[10],*c;
to
char arg[1000],c;
This line
scanf("%s",arg[1]);
to
scanf("%s",arg);
And this line
while((*c=getchar())!=EOF)
to
while((c=getchar())!=EOF)
Explanation:
char *c; is not a character. It's a pointer to a character. It starts out just pointing to a random bit of memory, which will often be filled with random data - whatever was most recently written there.
char c; is a character.
The same thing applies to char *arg[10]. It's an array of ten pointers. They point into random memory, filled with random data.
Note: my change is not best practice. If someone were to type in a filename 1000 characters or more long, you'd write over the end of the arg buffer. Depending on what you're doing, this can be a security bug.
In
char *arg[10];
you define an array of 10 pointers to char but you do not initialize its elements. arg[0], arg[1], ..., arg[9] will all have undefined values.
Then, you try to enter a string into one of those undefined values. Lucky you, you got a segmentation fault. Had you been unlucky, your program could format your hard disk instead.
char *arg[10] ;
arg is array of char pointers. You need to assign them memory locations using malloc before taking input -
scanf("%s",arg[1]); // arg[1] is not assigned to point to any memory location
// and is what causing the segmentation fault.
So do -
arg[1] = malloc( stringLengthExpectedToEnter + 1 ) ; // +1 for termination character
Should do like that with the rest of array elements too (or) simply change char*arg[10] to char arg[10] and make sure to enter only enter 9 characters.
I think you are confusing between a pointer and a normal variable.
int *ptr;
ptr is variable that can hold the address of an integer variable. Memory is allocated to for ptr variable to hold an integer address. That's it. ptr is in an uninitalized state and is pointing no where (or) might be pointing to garbage. Dereferencing an uninitialized pointer's behavior is undefined and you are lucky enough if it gives a segmentation-fault.
Now, you need to assign it a valid memory location using malloc.
ptr = malloc( sizeof(int) ) ; // Allocates number of bytes required to hold an
// integer and returns it's address.
So, ptr is now pointing to memory location acquired from free store that can hold an integer. Such acquired locations from free stored must be freed using free, else you have classical problem of memory leak. It is good practice to initialize pointer to NULL while declaration.
int *ptr = NULL ;
Hope it helps !
scanf("%d", ptr) ; // Notice that & is not required before ptr. Because ptr
// content is address itself.
A normal variable story is entirely different. When declared -
int var ;
Memory is allocated to var to hold an integer. So, you can directly assign it an integer.
#include<stdio.h>
int main()
{
char arg[10],c;
int count=0;
FILE *fp;
printf("Name of the file:");
scanf("%s",arg);
fp=fopen(arg,"w");
printf("\t\t%s",arg);
printf("Input the text into the file\n");
printf("Press Ctrl+d to the stop\n");
while((c=getchar())!=EOF)
{
fwrite(&c,sizeof(char),1,fp);
count++;
}
if(fp != NULL){
fclose(fp);
fp = NULL;
}
return 0;
}

Resources