This program work,
It reads a big log file line by line , After reading 3 lines , it shows segmentation fault .
int main(int argc, char *argv[])
{
char *line;
FILE *my_stream;
char *my_filename = "log";
my_stream = fopen (my_filename, "r");
while(fscanf (my_stream, "%s", &line)!= EOF)
{
printf ("==> %s\n", &line);
}
fclose (my_stream);
return 0;
}
OUTPUT
==> 123 ==> 12345 ==> 1234568 Segmentation fault
You haven't allocated memory for line. Either declare it as:
char line[256];
Or do an malloc for it.
Note: you don't need & neither in scanf nor in printf if you are dealing with a string (%s format specifier)
You need to allocate space for line either on the stack or the heap. Also do not pass the address of line to fscanf and printf.
int main(int argc, char *argv[])
{
char line[256];
FILE *my_stream;
char *my_filename = "log";
my_stream = fopen (my_filename, "r");
while(fscanf (my_stream, "%255s", line)!= EOF)
{
printf ("==> %s\n", line);
}
fclose (my_stream);
return 0;
}
You have not allocated any space at all for the line. fscanf is thus writing your logfile's lines into memory at some random location and clobbering whatever happens to be there. You get lucky three times and then it blows up.
For this task you should ideally be using getline. If you don't have that, fgets will do, but you will need to allocate it some space. Think char linebuf[SOME LARGE NUMBER].
Never use *scanf.
In the line char *line you allocate space for one pointer to a char. In your fscanf statement you read whole lines of text into that address. You never allocate any space for the text that you read with fscanf, so you overwrite lots of memory that is used for other things.
Related
I need to read an input .txt file and print out two separate strings from each line in the file. I used a while loop and a fscanf function to get each string and ignore blank space between. If the strings in a line of the input file are too long, I get a segmentation fault. However, I am also getting a munmap_chunk(): invalid pointer error when I run my executable.
If I don't allocate memory for string1 and string2, fscanf doesn't work properly. I believe fscanf is changing the pointers to string1 and string2, which is causing the munmap_chunk() error. However, I need to de-allocate the memory I gave string1 and string2 so I don't have memory leaks.
How do I scan this file for strings (of ANY length) and de-allocate the memory properly?
int main(int argc, char *argv[])
{
char *string1;
char *string2;
string1 = (char *)malloc(sizeof(string1)); //these strings need memory allocated for the fscanf to function properly
string2 = (char *)malloc(sizeof(string2));
FILE* file = fopen(argv[1], "r");
while (fscanf(file, "%s %s", string1, string2) != EOF)
{
printf("%s %s\n", string1, string2);
}
fclose(file);
//Deallocating memory
free(string1);
free(string2);
return 0;
}
'fscanf' does not change pointers but it can corrupt memory if you do not allocate enough space for your input.
And you are not allocating the memory correctly: string1 and string2 are pointers, so all you are allocating is a size of a pointer (4 or 8 bytes depending on your system).
If you need to read a line from a file and you do not know the maximum length of the line in advance, you can not use fscanf.
You need to allocate a starting buffer, say something like:
string1 = malloc(512 * sizeof(char));
Were 512 is an arbitrary but reasonably large length for a line.
You then use fread to read one byte at a time in a loop, and check for end of line (usually '\n').
You must also count how much you read, and if the line is longer than 512 bytes, use realloc to increase the size of your buffer, like so:
if (bytesRead == (string1Size - 1) && curByte != '\n') {
string1Size += 512;
string1 = realloc(string1, string1Size);
}
Here, bytesRead is an int variable counting how many bytes you successfully read so far, and string1Size is also int variable used to track the size of string1 buffer.
string1 = (char *)malloc(sizeof(string1)); allocates memory for just 4 or 8 characters because string1 is a char * and that's how big a pointer is.
To allocate memory for let's say 100 characters you need to do char *string1 = malloc(sizeof(char) * 100).
How do I scan this file for strings (of ANY length) and de-allocate the memory properly?
You can't with fscanf because it mixes reading input with parsing input. You don't know what's going to be read before you parse it.
Instead, read the line into a large buffer where you can examine it. Once you know how big the pieces are you can allocate just the right amount of memory and copy to it.
Because we are reusing the line buffer, and throwing it away when we're done, we can make it as large as we think we'll ever need. 1024 or 4096 are often good choices. I like BUFSIZ.
char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
// now parse line
}
The parsing can be done in various ways. A simple one is strtok (STRing TOKenize). This tokenizes line in place. Copy them to the right amount of memory with strdup.
char line[BUFSIZ];
while( fgets(line, sizeof(line), file) ) {
char words[2];
int i = 0;
for(
char *word = strtok(line, " ");
word;
word = strtok(NULL, " ")
) {
words[i] = strdup(word);
i++;
}
printf("%s %s", words[0], words[1]);
free(words[0]);
free(words[1]);
}
line and words are allocated on the stack, they will be freed automatically. But the memory allocated by strdup is on the heap, it needs to be freed.
I'm new user in stackoverflow. I wrote this code in c and I have no problem and the output is correct.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *str[10];
FILE * fp;
fp = fopen ("file.txt", "w+");
fputs("We\nare\nin\n2016", fp);
rewind(fp);
fscanf(fp, "%s", str[0]);
fscanf(fp, "%s", str[1]);
printf("Read String1 |%s|\n", str[0] );
printf("Read String2 |%s|\n", str[1] );
fclose(fp);
return(0);
}
but when I use char *str[15] instead of char *str[10], the result is segmentation fault. What is wrong?
The pointers str[0] and str[1] are uninitialized. So, your program has undefined behaviour.
Either you need to allocate using malloc() or make them an array of arrays (e.g. str[2][256];) with fixed length that's sufficient enough for the strings you read from the file.
In any case, I'd personally use fgets() instead of fscanf() and then parse the line as necessary.
It would also help to do error checking for all functions (fopen(), fscanf(), etc).
Keep in mind you are declaring char * str[10], you are reserving memory for ten pointers but you didn't call malloc to reserve memory for the contents of these pointers.
Your example seems similar to this tutorial of the function fscanf, http://www.tutorialspoint.com/c_standard_library/c_function_fscanf.htm.
But there, string parts are declared as char[10] instead of char *[10] which means they already have memory reserved for 10 characters. In this same example reading a string with length greater than 10 will also generate problems.
I'm writing a status function but nothing except for the "Tracked:" is printing out. Can anyone see why? I'm assuming that the '.index' file is just a line by line list of file names.
int git_status() {
FILE *check = fopen(".git/.index", "r");
int count = 0;
char *pointer;
printf("Tracked:\n\n");
while(fgets(pointer, sizeof(pointer), check)){
strtok(pointer, "\n");
printf("%s\n", pointer);
count++;
}
printf("\n%d is the number of files", count);
fclose(check);
}
In C you need to allocate the memory you want for strings. In your case you need to declare either a array of characters with fixed length or dynamically reserve enough memory to contain the characters you are about to read.
For instance, the following is not very safe because p does not point to any memory, it is just an uninitialized address:
char* p;
strcpy(p, "This is a string");
If your lucky your compiler should warn you when you try to do things like the above (you might need to enable warnings, -Wall on gcc).
A better approach might be
char chArray[20];
strcpy(chArray, "This is a string");
or
char *p = malloc(20);
strcpy(p, "This is a string");
free(p);
As for char *fgets(char *s, int size, FILE *stream) you probably want to do something like:
#define BUFFER 128
char buf[BUFFER];
while (fgets(buf, BUFFER, fp) != NULL) { /* TODO */ }
To get your program running you will also probably need to look at how strtok works:
The strtok() function breaks a string into a sequence of zero or
more
nonempty tokens. On the first call to strtok() the string to be parsed
should be specified in str. In each subsequent call that should parse
the same string, str must be NULL.
Switching to C from Java, and I'm having some troubles grasping memory management
Say I have a function *check_malloc that behaves as such:
// Checks if malloc() succeeds.
void *check_malloc(size_t amount){
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if ( tpt == NULL ){
fprintf(stderr, "No memory of %lu bytes\n", amount);
exit(1);
}
return tpt;
}
I also have the following variables to work with:
FILE *f = fopen("abc.txt", "r"); // Pointer to a file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
}
My goal is to use *check_malloc to dynamically allocate memory so that the String pointed to by *pname is just the correct size for storing "mynamisbob", which is the only thing on the first line of the text file.
Here is my (failed) attempt:
int main(int argc, char *argv[]){
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
char currentline[150]; // Char array for storing current line of file
while(!feof(f)){
fgets(currentline,100,f);
pname = ¤tline;
}
But I know this probably isn't the way to go about this, because I need to use my nice check_malloc* function.
Additionally, in my actual text file there is a "<" symbol before the name on the first line.But I just want the *pname to point to a String saying "mynameisbob" without the "<" symbol. This isn't that important now, it just is reinforcement to me that I know I can't just set the pointer to point straight to currentline.
Can anyone help me fix my thinking on this one? Thanks a lot.
In C you need to copy chars, not the "strings" (which are just pointers). Check out strcpy() and strlen(). Use strlen() to determine how long the line actually is which fgets has read, then use your malloc() to allocate exactly that (plus 1 for the 0). Then copy the chars over with strcpy().
There are several problems in your code, see my comments in this example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Checks if malloc() succeeds.
void *check_malloc (size_t amount) {
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if (tpt == NULL) {
fprintf (stderr, "No memory of %lu bytes\n", amount);
exit (EXIT_FAILURE);
}
return tpt;
}
// To avoid subtle errors I have defined buffer size here
#define BUFFER_SIZE 150
// I have used the (void) version of main () here, while not strictly neccessary, you where not using argc and argv anyway, so the can be left out in this case
int main (void) {
// It might be a good idea to make the filename a char[] as well, but I leave that as an exercise to the reader.
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
// You have to check whether the file was *actually openend*
if (f == NULL) {
fprintf (stderr, "Could not open file abc.txt\n"); // '"...%s\n", filename);' might better.
exit (EXIT_FAILURE);
}
char *pname; // Pointer to a string for storing the name
char currentline[BUFFER_SIZE]; // Char array for storing current line of file
while(!feof (f)) {
char *res = fgets (currentline, BUFFER_SIZE, f);
// fgets returns NULL when EOF was encountered before the next '\n'
if (res) {
size_t read = strlen (res);
// The line might have been empty
if (read) {
// Better use "sizeof *varname", while char is always 1 byte it is a good practice
pname = check_malloc ((read + 1) * sizeof *pname); // + 1 because we have to provide an extra char für '\0'
strncpy (pname, currentline, read); // You have to use strcpy or strncpy to copy the contents of the string rather than just assigning the pointer
// What was allocated must be freed again
free (pname);
}
}
}
fclose(f); // Always close everything you open!
return EXIT_SUCCESS;
}
Actually you really don't have to use pname in this simple case, because currentline already contains the line, but since you're trying to learn about memory management this should give you a general idea of how things work.
In your code you had this line:
pname = ¤tline;
There are two problems here:
As already mentioned in my code assigning currentline to pname only copies the pointer not the contents.
The correct assignment would be pname = currentline (without the address operator &), because currentline is also a pointer under the hood (it behaves like char *currentline even though it's statically allocated).
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