segmentation fault on reading in a data file - c

I am trying to read in a file of characters into an array of 64 characters. the file reading happens in main()
int main (int argc, char **argv)
{
FILE *fp;
char write_msg[BUFFER_SIZE];
fp = fopen("test.data", "r");
int i;
for ( i = 0; i < (BUFFER_SIZE-1); i++){
fscanf(fp, "%s\n", &write_msg[i]);
printf ("printing in the for loop");
}
fclose(fp);
printf("Starting the main().\n");
printf("in Reader, the msg is: %s\n",write_msg);
pid_t pid;
int fd[2];
I keep getting a seg fault and I am not sure what I am doing

fscanf(fp, "%s\n", &write_msg[i]); should be fscanf(fp, "%c\n", &write_msg[i]);, you don't want to scan a string into a char.
And the write_msg should ends with a '\0', write_msg[BUFFER_SIZE-1]=0

I see the following problem in your code:
fscanf(fp, "%s\n", &write_msg[i]);
You are attempting to read a string starting at position i that is moving within your loop. It will be very easy to get a segmentation fault when i reaches the end of the memory reserved for the string write_msg.
Another recommendation: Put a validation on your fp descriptor:
fp = fopen("test.data", "r");
if ( fp == NULL ) {
/* Show an error and exit */
}
If for any reason the file could not be read, fp will be NULL and as segmentation fault would be raised.

You're scanning a string, which might be rather long, into a buffer without limiting how many characters will be read. You shouldn't do that. You're then incrementing i by one, even though the string might be much longer. You should use fgets or fread to read the entire file into your buffer, since you really don't need the special features of fscanf, and those functions will take a length of characters to read. Or if you really really like your for loop, you could use fgetc, which does exactly what you think fscanf is doing.

Related

Storing String Inside a String?

My problem is when I try to save the string (series[0]) Inside (c[0])
and I display it, it always ignore the last digit.
For Example the value of (series[0]) = "1-620"
So I save this value inside (c[0])
and ask the program to display (c[0]), it displays "1-62" and ignores the last digit which is "0". How can I solve this?
This is my code:
#include <stdio.h>
int main(void)
{
int price[20],i=0,comic,j=0;
char name,id,book[20],els[20],*series[20],*c[20];
FILE *rent= fopen("read.txt","r");
while(!feof(rent))
{
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
i++;
}
c[0]=series[0];
printf("\n%s",&c[0]);
return 0;
}
The use of fscanf and printf is wrong :
fscanf(rent,"%s%s%s%d",&book[i],&els[i],&series[i],&price[i]);
Should be:
fscanf(rent,"%c%c%s%d",&book[i],&els[i],series[i],&price[i]);
You have used the reference operator on a char pointer when scanf expecting a char pointer, also you read a string to book and else instead of one character.
printf("1.%s %s %s %d",&book[i],&els[i],&series[i],price[i]);
Should be:
printf("1.%c %c %s %d",book[i],els[i],series[i],price[i]);
And:
printf("\n%s",&c[0]);
Should be:
printf("\n%s",c[0]);
c is an array of char * so c[i] can point to a string and that is what you want to send to printf function.
*Keep in mind that you have to allocate (using malloc) a place in memory for all the strings you read before sending them to scanf:
e.g:
c[0] = (char*)malloc(sizeof(char)*lengthOfString+1);
and only after this you can read characters in to it.
or you can use a fixed size double character array:
c[10][20];
Now c is an array of 20 strings that can be up to 9 characters long.
Amongst other problems, at the end you have:
printf("\n%s",&c[0]);
There are multiple problems there. The serious one is that c[0] is a char *, so you're passing the address of a char * — a char ** — to printf() but the %s format expects a char *. The minor problem is that you should terminate lines of output with newline.
In general, you have a mess with your memory allocation. You haven't allocated space for char *series[20] pointers to point at, so you get undefined behaviour when you use it.
You need to make sure you've allocated enough space to store the data, and it is fairly clear that you have not done that. One minor difficulty is working out what the data looks like, but it seems to be a series of lines each with 3 words and 1 number. This code does that job a bit more reliably:
#include <stdio.h>
int main(void)
{
int price[20];
int i;
char book[20][32];
char els[20][32];
char series[20][20];
const char filename[] = "read.txt";
FILE *rent = fopen(filename, "r");
if (rent == 0)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
return 1;
}
for (i = 0; i < 20; i++)
{
if (fscanf(rent, "%31s%31s%19s%d", book[i], els[i], series[i], &price[i]) != 4)
break;
printf("%d. %s %s %s %d\n", i, book[i], els[i], series[i], price[i]);
}
printf("%d titles read\n", i);
fclose(rent);
return 0;
}
There are endless ways this could be tweaked, but as written, it ensures no overflow of the buffers (by the counting loop and input conversion specifications including the length), detects when there is an I/O problem or EOF, and prints data with newlines at the end of the line. It checks and reports if it fails to open the file (including the name of the file — very important when the name isn't hard-coded and a good idea even when it is), and closes the file before exiting.
Since you didn't provide any data, I created some random data:
Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
The output from the code above on that data is:
0. Tixrpsywuqpgdyc Yeiasuldknhxkghfpgvl 1-967 8944
1. Guxmuvtadlggwjvpwqpu Sosnaqwvrbvud 1-595 3536
2. Supdaltswctxrbaodmerben Oedxjwnwxlcvpwgwfiopmpavseirb 1-220 9698
3. Hujpaffaocnr Teagmuethvinxxvs 1-917 9742
4. Daojgyzfjwzvqjrpgp Vigudvipdlbjkqjm 1-424 4206
5. Sebuhzgsqpyidpquzjxswbccqbruqf Vuhssjvcjjylcevcisdzedkzlp 1-581 3451
6. Doeraxdmyqcbbzyp Litbetmttcgfldbhqqfdxqi 1-221 2485
7. Raqqctfdlhrmhtzusntvgbvotpk Iowdcqlwgljwlfvwhfmw 1-367 3505
8. Kooqkvabwemxoocjfaa Hicgkztiqvqdjjx 1-466 435
9. Lowywyzzkkrazfyjuggidsqfvzzqb Qiginniroivqymgseushahzlrywe 1-704 5514
10 titles read

Reading line by line C

I have a txt file with some file names and their size.
This is how I wrote the txt file:
banana //file name
3 //the size of file banana
programs
12
music
524
I have to find a keyboard entered file name and display it's size.
This is my code:
FILE *text;
text=fopen("text.txt","r");
printf("Scan the number of letters of your file name");
int n;
scanf("%d",&n);
char s[++n];
printf("Scan the file name you are looking for: ");
int i;
for(i=0;i<=n;i++)
{
scanf("%c",&s[i]);
}
int l=0;
char c[n];
char g;
while(!feof(text))
{
if(l%2==1) {fgetc(text); fgetc(text); l++;}
if(l%2==0)
{
fgets(c,n,text);
fgetc(text);
for(i=0;i<n;i++)
{
printf("%c",c[i]);
}
l++;
}
}
Obviously, it's not correct. Can you help me? I'm a little bit confuse.
Ugh! Please learn more about basic input. Your program has various flaws:
fgetc reads single characters. This can be useful at times, but obviously you want to read whole lines. fgets does this. You use it once, but it is not advisable to mix these. Decide up front which input paradigm you want to use: char-wise (fgetc), line-wise (fgets) or token-wise (fscanf).
Please don't make the user enter the number of characters in the filename. Quick, how many characters are there in MySpiffyDocument.txt? That's work that the computer should do.
Don't use feof to control yopur input. All input functions have special return values toat indicate that either the end of the file was read or that an error occurred. For fgets, this return value is NULL, for fgetc, this return value is the special constant EOF. The functions feof and ferror are useful after you have encountered the special return values for a post mortem analysis of the two end conditions.
Your inner loop, which is responsible for the core program logic, doesn't make sense at all. For example, for an odd l, increment l and then test for an even l – which will be true, because you have just incrremented an odd l. Use else in such cases. And don't place things that happen anyway in conditional blocks: Increment l once after the if/else blocks.
Here's an example implementation:
#include <stdlib.h>
#include <stdio.h>
int process(const char *filename)
{
char line[80];
char name[80];
int size;
int count = 0;
FILE *f = fopen(filename, "r");
if (f == NULL) return -1;
while (fgets(line, sizeof(line), f)) {
if (count % 2 == 0) {
if (sscanf(line, "%s", name) < 1) continue;
} else {
if (sscanf(line, "%d", &size) < 1) continue;
printf("%12d %s\n", size, name);
}
count++;
}
fclose(f);
return 0;
}
int main()
{
char line[80];
char name[80];
puts("Please enter filename:");
while (fgets(line, sizeof(line), stdin)) {
if (sscanf(line, "%s", name) == 1) {
process(name);
break;
}
}
return 0;
}
Things to note:
The program uses 80 characters a max. buffer size; that means your lines can be up to 78 characters long – line content plus new-line '\n' plus null terminator '\0'. That should be okay for many cases, but eventually the line may overflow. (So your file-name letter count has some merit, but the real solution here is to allocate memory dynamically. I won't open that can of worms now.)
The code uses a double strategy: Read lines first, then scan into these lines with sscanf, so that only the first word on each line is read.
Empty lines are skipped. Even lines that don't hold a valid number are skipped, too. This is sloppy error handling and may trip the odd/even count.
Reading stuff interactively from the keyboard isn't very easy in C. The awkward fgets/sscanf construct in main tries to handle the case when the user enters an empty line or evokes an end-of-file signal via Ctrl-D/Z. A better and easier way is to provide arguments to the command line via argc and argv.
I've moved the file reading into a separate function.

Read Magic Number from .au File

I wrote a small program to get the magic number from an .au file and print it to console, but every time I try, instead of getting the intended .snd, I get .snd$ instead.
I'm not sure why this is happening, considering that I'm only reading in 4 bytes, which is what the magic number is comprised of. So, where is the extra character coming from?
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[4], path[20];
scanf("%s", path);
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
printf("magic number is %s\n", m);
return 0;
}
You're printing it as though it were a string, which in C, means that it's NUL-terminated. Change your code like this and it will work as you expect:
char m[5];
m[4] = '\0'; /* add terminating NUL */
Also, you should be aware that scanf is a dangerous function. Use a command line argument instead.
The problem is not how you are reading.
The problem is that your variable is only 4 chars length, and it needs a null character to indicate the end.
printf with %s will print the content of the variable until reach a null character, until that it can print garbage if your variable is not correctly ended.
To fix you can have a bigger variable and set the [4] char with null.
How the new code should look like:
#include <stdio.H>
int main()
{
FILE *fin;
int r;
char m[5], path[20];
scanf("%s", path);
/*Scanf can be dangerous because it can cause buffer overflow,
it means that you can fill your variable with more bytes than it supports, which can end up being used for buffer overflow attacks:
See more: http://en.wikipedia.org/wiki/Buffer_overflow */
fin = fopen(path, "r");
r = fread(&m, sizeof(char), 4, fin);
m[4] = '\0';
printf("magic number is %s\n", m);
return 0;
}

Reading big numbers such as e and pi from files to arrays in C

I have a file called pi.txt which contains, as you probably imagine, the numbers of pi.
The format goes like this
Line 1: 3.
Line 2: 14159265358979323846264338327950288419716939937510
Line 3: 58209749445923078164062862089986280348253421170679
and it continues to
Line 20001: 56787961303311646283996346460422090106105779458151
There are 1020001 digits minus the 3 and the .(of 3.14xxxxxx...)
I have to read this file to an array (not a 2D one. What I want to do later will become much harder if I use a 2D array as I imagine it). This is my code:
void fpi();
char **arraypi;
int main(int argc, char *argv[]) {
fpi();
int i;
while (i<=10){
printf("%d", arraypi[i++]);}
return 0;
}
void fpi(){
char pi[1020001];
arraypi = malloc(1020001 * sizeof(int));
FILE *file;
int i=0;
file = fopen("pi.txt", "r");
if (file == NULL){
printf("The file cannot be opened.\n");
exit(1);
}
while (fscanf(file, "%c", &pi)==1){
strcpy(arraypi[i++], pi);
}
fclose(file);
}
I get a segmentation fault and I can't figure out why. I'm sure it has to do with the pointers I'm using and fscanf.
strcpy expects you to give a null terminated character array (string) and you're giving an array of 1020001 characters where except the first character, which is read from the file, everything else is undetermined.
char pi[1020001];
while (fscanf(file, "%c", &pi)==1){ // only one character gets copied to pi
strcpy(arraypi[i++], pi); // strcpy will expect pi to be a string and not just a char
}
Hence it may go on an infinite loop and write beyond the allowed memory allocated for it, thereby corrupting the stack structure and thus leading to the segmentation fault. You're also treading on undefined behaviour when you're doing this.

confused by C syntax

i'm new at c.. and still having trouble at the syntax, hope you can help me... cause i'm stuck at this code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void){
FILE *stream = NULL;
stream = fopen("studentinfo.txt", "a+");
/*some of initialization were used for testing purposes only*/
char arr[5];
char arr2[5];
int i;
char name[3];
char course[5];
printf("enter details: ");
scanf("%s", arr2);
while(!feof(stream)){
fgets(arr, 100, stream);//i am confused if the line capture was stored at arr[0]
if(strcmp(arr, arr2)==0){//i want to compare
printf("success");//testing
}
printf("%s", arr);//i wonder does fgets just overwrites the new line to arr[0]
}
fclose(stream);
getch();
}
thanks guys...
You're opening studentinfo.txt for appending, but then reading from it (and you don't check the open succeeded
you've allocated 5 characters for arr, but read up to 100 characters into it with the fgets. This will overflow and cause memory corruption
you've allocated 5 characters for arr2, but read an arbitary number of characters into it - this will overflow and cause memory corruption
Fgets reads characters into memory starting at arr. arr[0] is the first character. &arr[0] is the same as arr
What's the getch() at the end for?
Also, "a+" positions the stream at the end of the file, so you won't be able to read anything.
if you have an existing file... and your file has data on it. then you could check if the data you typed is existing on the file or not. i'm not sure if this is what you want.
example if you typed... love
and the file also contains the exact word... love (on one line)
then it will print "success".
if the data you typed is not existing on the file, it will be appended on the file (on the next line).
int main(void){
char arr[5];
char arr2[5];
int i;
int n=0;
FILE *stream = NULL;
FILE *append = NULL;
stream = fopen("studentinfo.txt", "rt");
append = fopen("studentinfo.txt", "a+");
printf("enter details: ");
scanf("%s", arr2);
while(!feof(stream)){
fgets(arr, 6, stream);
if(strcmp(arr, arr2)==0){
printf("success");
} else n=-1;
}
if (n==-1){
fprintf(append, "%s\n", arr2);
}
fclose(stream);
fclose(append);
system("pause");
}
I am not sure why you are opening the stream with a+ because you never actually write to it. Maybe you want to make sure the file exists even if 0 length? You should still check that the open succeeded though.
You are then reading 100 characters into an array of just 5 bytes so you will get a serious memory overwrite if the file really does contain that number.
The scanf is unsafe too of course as the user may enter too many characters (they are actually limited to 4 because there is a NULL terminator that gets read).
At the end you appear to be writing the last line randomly if the user did not enter a matching line from the file.

Resources