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.
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.
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
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.
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.
I am getting "Bus Error" trying to read stdin into a char* variable.
I just want to read whole stuff coming over stdin and put it first into a variable, then continue working on the variable.
My Code is as follows:
char* content;
char* c;
while( scanf( "%c", c)) {
strcat( content, c);
}
fprintf( stdout, "Size: %d", strlen( content));
But somehow I always get "Bus error" returned by calling cat test.txt | myapp, where myapp is the compiled code above.
My question is how do i read stdin until EOF into a variable? As you see in the code, I just want to print the size of input coming over stdin, in this case it should be equal to the size of the file test.txt.
I thought just using scanf would be enough, maybe buffered way to read stdin?
First, you're passing uninitialized pointers, which means scanf and strcat will write memory you don't own. Second, strcat expects two null-terminated strings, while c is just a character. This will again cause it to read memory you don't own. You don't need scanf, because you're not doing any real processing. Finally, reading one character at a time is needlessly slow. Here's the beginning of a solution, using a resizable buffer for the final string, and a fixed buffer for the fgets call
#define BUF_SIZE 1024
char buffer[BUF_SIZE];
size_t contentSize = 1; // includes NULL
/* Preallocate space. We could just allocate one char here,
but that wouldn't be efficient. */
char *content = malloc(sizeof(char) * BUF_SIZE);
if(content == NULL)
{
perror("Failed to allocate content");
exit(1);
}
content[0] = '\0'; // make null-terminated
while(fgets(buffer, BUF_SIZE, stdin))
{
char *old = content;
contentSize += strlen(buffer);
content = realloc(content, contentSize);
if(content == NULL)
{
perror("Failed to reallocate content");
free(old);
exit(2);
}
strcat(content, buffer);
}
if(ferror(stdin))
{
free(content);
perror("Error reading from stdin.");
exit(3);
}
EDIT: As Wolfer alluded to, a NULL in your input will cause the string to be terminated prematurely when using fgets. getline is a better choice if available, since it handles memory allocation and does not have issues with NUL input.
Since you don't care about the actual content, why bother building a string? I'd also use getchar():
int c;
size_t s = 0;
while ((c = getchar()) != EOF)
{
s++;
}
printf("Size: %z\n", s);
This code will correctly handle cases where your file has '\0' characters in it.
Your problem is that you've never allocated c and content, so they're not pointing anywhere defined -- they're likely pointing to some unallocated memory, or something that doesn't exist at all. And then you're putting data into them. You need to allocate them first. (That's what a bus error typically means; you've tried to do a memory access that's not valid.)
(Alternately, since c is always holding just a single character, you can declare it as char c and pass &c to scanf. No need to declare a string of characters when one will do.)
Once you do that, you'll run into the issue of making sure that content is long enough to hold all the input. Either you need to have a guess of how much input you expect and allocate it at least that long (and then error out if you exceed that), or you need a strategy to reallocate it in a larger size if it's not long enough.
Oh, and you'll also run into the problem that strcat expects a string, not a single character. Even if you leave c as a char*, the scanf call doesn't make it a string. A single-character string is (in memory) a character followed by a null character to indicate the end of the string. scanf, when scanning for a single character, isn't going to put in the null character after it. As a result, strcpy isn't going to know where the end of the string is, and will go wandering off through memory looking for the null character.
The problem here is that you are referencing a pointer variable that no memory allocated via malloc, hence the results would be undefined, and not alone that, by using strcat on a undefined pointer that could be pointing to anything, you ended up with a bus error!
This would be the fixed code required....
char* content = malloc (100 * sizeof(char));
char c;
if (content != NULL){
content[0] = '\0'; // Thanks David!
while ((c = getchar()) != EOF)
{
if (strlen(content) < 100){
strcat(content, c);
content[strlen(content)-1] = '\0';
}
}
}
/* When done with the variable */
free(content);
The code highlights the programmer's responsibility to manage the memory - for every malloc there's a free if not, you have a memory leak!
Edit: Thanks to David Gelhar for his point-out at my glitch! I have fixed up the code above to reflect the fixes...of course in a real-life situation, perhaps the fixed value of 100 could be changed to perhaps a #define to make it easy to expand the buffer by doubling over the amount of memory via realloc and trim it to size...
Assuming that you want to get (shorter than MAXL-1 chars) strings and not to process your file char by char, I did as follows:
#include <stdio.h>
#include <string.h>
#define MAXL 256
main(){
char s[MAXL];
s[0]=0;
scanf("%s",s);
while(strlen(s)>0){
printf("Size of %s : %d\n",s,strlen(s));
s[0]=0;
scanf("%s",s);
};
}