read ASCII code file using fscanf - c

I am trying to read an ASCII text file and write it into binary file. The text file is unlimited in size. First, I tried to read the text file before writing it. However, I keep getting segmentation fault. I don't understand what may cause the problem. Even using gdb, I still cannot figure out the problem. Please advise.
Code:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
typedef struct _FileData
{
int a;
double b;
char dataStr[56];
}FileData;
int main()
{
FILE * infile=fopen("output.txt", "r");
if(infile==NULL)
{
printf("Error opening file");
exit(1);
}
FileData **input;
int i=0;
while( fscanf(infile,"%d %f %[^\n]s",&input[i].a,&input[i].b,&input[i].dataStr)! =NULL)
{
printf("%d",input[i].a);
printf("%.3f",input[i].b);
printf("%[^\n]s",input[i].dataStr);
i++;
}
return 0;
}
My text file is
47
34.278
This is a line of text
48
23.678
This a very very long line
49
12.4569
This a very short line
50
117.906
This world is so beautiful
51
34.789
Hello world!

The problem in your code is that you have a pointer:
FileData** input;
You are using that pointer even though it's not been initialized to point to any valid memory.
Since you are writing the data out to stdout immediately after reading from the file, you can use:
FileData input;
while( fscanf(infile,"%d %lf %55[^\n]",&input.a, &input.b, input.dataStr) == 3)
// Notice the chage here
{
printf("%d",input.a);
printf("%.3f",input.b);
printf("%s\n",input.dataStr);
}
But then, I don't understand the need for struct _FileData. You can just as easily use:
int intValue;
double doubleValue;
char stringValue[56];
while( fscanf(infile,"%d %lf %55[^\n]",&intValue, &doubleValue, stringValue) == 3)
{
printf("%d %.3f %s\n",intValue, doubleValue, stringValue);
}

Related

C Using char* in fscanf causing error Segmentation fault: 11

I am new to C and I came across an issue when using fscanf to read all strings from a .txt file.
The code is as follow:
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn;
char *numIn;
spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
}
while ((fscanf(spIn, "%s", numIn)) == 1) {
printf("%s\n", numIn);
};
fclose(spIn);
return 1;
}
This throws an error: Segmentation fault: 11.
The original data on txt file is:
1 2 345 rrtts46
dfddcd gh 21
789 kl
a mix of ints, strings, white space and newline characters.
At least 4 candidate undefined behaviors (UB) that could lead to a fault of some kind.
Code fails to pass to fscanf(spIn,"%s",numIn) an initialized pointer.
Code calls fscanf() even if fopen() fails.
Code calls fclose() even if fopen() fails.
No width limit in fscanf(spIn,"%s",numIn)), worse than gets().
Text files really do not have strings ('\0' terminated data) nor int, they have lines (various characters with a '\n' termination).
To read a line in and save as a string, use fgets(). Do not use fscanf() to read lines of data.
#include <stdlib.h>
#include <stdio.h>
int main() {
FILE *spIn = fopen("data.txt", "r");
if (spIn == NULL) {
printf("Can't Open This File \n");
} else {
char buf[100];
while (fgets(buf, sizeof buf, spIn)) {
printf("%s", buf);
}
fclose(spIn);
}
}
char* numIn is a pointer, and it is uninitalized, you can't really store anything in it, you need to either allocate memory for it or make it point to some valid memory location:
#include<stdlib.h> // for malloc
char* numIn = malloc(100); // space for 99 char + null terminator byte
//...
while ((fscanf(spIn, "%99s", numIn)) == 1)
{
printf("%s\n",numIn);
};
Or:
char str[100];
char *numIn = str;
Which in this small code makes little sense, you should probably make numIn a fixed size array to begin with:
char numIn[100];
Note that that you should use a width specifier in *scanf to avoid buffer overflow. This still has a problem though, it will read word by word, instead of line by line.
Looking at your input file, using fgets seems like a better option, it can read complete lines, including spaces:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
FILE *spIn;
char numIn[100];
spIn = fopen("data.txt", "r");
if (spIn != NULL)
{
while ((fgets(numIn, sizeof numIn, spIn)))
{
numIn[strcspn(numIn, "\n")] = '\0'; // removing \n
printf("%s\n", numIn);
}
fclose(spIn);
}
else
{
perror("Can't Open This File");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Since fgets also parses the \n character, I'm removing it with strcspn.
Though you do verify the return value of fopen the execution continues even if it fails to open, I also addressed that issue.

Reading and writing into a file in c

I need to write into a file with uppercase some strings ,then to display on screen with lowercase. After that ,I need to write into file the new text (lowercase one). I write some code ,but it doesn't work. When I run it , my file seems to be intact and the convert to lowercase don't work
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void main(void) {
int i;
char date;
char text[100];
FILE *file;
FILE *file1;
file = fopen("C:\\Users\\amzar\\Desktop\\PC\\Pregatire PC\\Pregatire PC\\file\\da.txt","r");
file1 = fopen("C:\\Users\\amzar\\Desktop\\PC\\Pregatire PC\\Pregatire PC\\file\\da.txt","w");
printf("\nSe citeste fisierul si se copiaza textul:\n ");
if(file) {
while ((date = getc(file)) != EOF) {
putchar(tolower(date));
for (i=0;i<27;i++) {
strcpy(text[i],date);
}
}
}
if (file1) {
for (i=0;i<27;i++)
fprintf(file1,"%c",text[i]);
}
}
There are several problems with your program.
First, getc() returns int, not char. This is necessary so that it can hold EOF, as this is not a valid char value. So you need to declare date as int.
When you fix this, you'll notice that the program ends immediately, because of the second problem. This is because you're using the same file for input and output. When you open the file in write mode, that empties the file, so there's nothing to read. You should wait until after you finish reading the file before you open it for output.
The third problem is this line:
strcpy(text[i],date);
The arguments to strcpy() must be strings, i.e. pointers to null-terminated arrays of char, but text[i] and date are char (single characters). Make sure you have compiler warnings enabled -- that line should have warned you about the incorrect argument types. To copy single characters, just use ordinary assignment:
text[i] = date;
But I'm not really sure what you intend with that loop that copies date into every text[i]. I suspect you want to copy each character you read into the next element of text, not into all of them.
Finally, when you were saving into text, you didn't save the lowercase version.
Here's a corrected program. I've also added a null terminator to text, and changed the second loop to check for that, instead of hard-coding the length 27.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
void main(void) {
int i = 0;
int date;
char text[100];
FILE *file;
FILE *file1;
file = fopen("C:\\Users\\amzar\\Desktop\\PC\\Pregatire PC\\Pregatire PC\\file\\da.txt","r");
printf("\nSe citeste fisierul si se copiaza textul:\n ");
if(file) {
while ((date = getc(file)) != EOF) {
putchar(tolower(date));
text[i++] = tolower(date);
}
text[i] = '\0';
fclose(file);
} else {
printf("Can't open input file\n");
exit(1);
}
file1 = fopen("C:\\Users\\amzar\\Desktop\\PC\\Pregatire PC\\Pregatire PC\\file\\da.txt","w");
if (file1) {
for (i=0;text[i] != '\0';i++)
fprintf(file1,"%c",text[i]);
fclose(file1);
} else {
printf("Can't open output file\n");
exit(1);
}
}

Struct Memory Allocation from File in C, only two variables work

I have to write a program that will read text from a file, break it up into a struct, validate the sections to a certain criteria, then produce two new files; one with the clean data and one with the errors. So far i am up to the stage of breaking up the data from a file and storing it into a struct but it will only work for the first two variables.
the text is separated by colons and i need to put each section into the variables bellow
an example of the text file
0001:0002:0003:0021:CLS
here is my struct
struct packet{
int source;
int destination;
int type;
int port;
char data[50];
};
Bellow is whatworks fine, however as soon as i add another section to add data to the type variable, the program does not work.
fscanf(inFile, "%[^:]: %[^:]:", records[i].source, records[i].destination);
printf("%d - %s _ %s", i+1, records[i].source, records[i].destination);
However this does not work and i need it to. Well i need to expand upon it.
fscanf(inFile, "%[^:]: %[^:]: %[^:]:", records[i].source, records[i].destination, records[i].type);
printf("%d - %s _ %s _ %s", i+1, records[i].source, records[i].destination, records[i].type);
}
if i printf without inputting anything to the struct it displays null as i would expect because nothing is being stored so im thinking that there is something wrong with the fscanf function. As it works for the first two, i dont think that it is a syntax issue so it must be a memory issue. I have used malloc and realloc but ive gotten confused with it and im sure that i have not done it right.
Full Code Listing
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//declaration of function which will print my name and student number
const char * myname();
//declaration of a function that will prompt a user to enter a file and open it if it exists
int openfile();
struct packet{
int source;
int destination;
int type;
int port;
char data[50];
};
int main()
{
int recordCount = 0;
struct packet *records;
records =malloc(sizeof(struct packet));
// printing the my name and student number via the myname function
printf("%s\n", myname());
//executing the openfile function that will open a function
openfile(recordCount, records);
return 0;
}
const char * myname()
{
const char *x = "*************************\nUSERNAME\nUSER NUMBER\nCONTACT NUMBER\n*************************\n";
return x;
}
int openfile(int rCount, struct packet *records)
{
//file pointer which will keep track of the file being accessed
FILE *inFile ;
//creating variable that will hold what the user has entered for a filename to open
char inFileName[100] = { '\0'};
printf("Please Enter the File to open:");
//getting the users input and storing it into the variable just created
scanf("%s", inFileName);
//if the file does not exist, display an appropriate error message
if ((inFile = fopen(inFileName, "r")) == NULL)
{
printf("Cannot Open File **%s**\n", inFileName) ;
exit(1) ;
}
else {
//if the file does exist, process the data
while(fgets(inFileName, 100, inFile)!=NULL)
{
int i =0;
for (i=0; i<30;i++)
{
fscanf(inFile, "%[^:]: %[^:]: %[^:]:", records[i].source, records[i].destination, records[i].type);
printf("%d - %s _ %s _ %s", i+1, records[i].source, records[i].destination, records[i].type);
}
}
//close the file
fclose(inFile);
return 0;
}
};
You're doing it wrong:
fscanf(inFile, "%[^:]: %[^:]:", records[i].source, records[i].destination);
The %[] conversion specifier is for string, but you're passing the values of integers as if they were character pointers. Undefined behavior!
You should be getting heaps of warnings for this from any modern compiler, i.e. one that validates formatting strings.
There's no point in parsing integers as if they were strings, I don't understand why you're not just doing
fscanf(inFile, "%d:%d", &records[i].source, &records.destination);
for the first case.
Also, do note that it's much better to read in whole lines using fgets(), then parsing the line once read using sscanf(), than trying to combine the two steps with fscanf().
Last, you should check the return value of the conversion call to know how many conversion succeeded.

Reading data from a text file in C?

So I'm pretty new at reading data from a text file in C. I'm used to getting input using scanf or hard coding.
I am trying to learn how to not only read data from a text file but manipulate that data. For example, say a text file called bst.txt had the following information used to perform operations on a binary search tree:
insert 10
insert 13
insert 5
insert 7
insert 20
delete 5
delete 10
....
With that example, I would have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fptr;
char *charptr;
char temp[50];
fptr = fopen("bst.txt", "r");
while(fgets(temp, 50, fptr) != NULL)
{
charptr = strtok(temp, " ");
while(charptr != NULL)
{
charptr = strtok(NULL, " ");
}
}
return 0;
}
I know that within the first while loop strtok() splits each line in the text file and within the second while loop strtok() splits off when the program recognizes a space, which in this case would separate the operations from the integers.
So my main question is, after, for example, the word "insert" is separated from the integer "10", how do I get the program to continue like this:
if(_____ == "insert")
{
//read integer from input file and call insert function, i.e. insert(10);
}
I need to fill in the blank.
Any help would be greatly appreciated!
If I were doing what you're doing, I would be doing it that way :)
I see a lot of people getting upvoted (not here, I mean on SO generally) for recommending that people use functions like scanf() and strtok() despite the fact that these functions are uniformly considered evil, not just because they're not thread-safe, but because they modify their arguments in ways that are hard to predict, and are a giant pain in the ass to debug.
If you're malloc()ing an input buffer for reading from a file, always make it at least 4kB — that's the smallest page the kernel can give you anyway, so unless you're doing a bazillion stupid little 100-byte malloc()s, you might as well — and don't be afraid to allocate 10x or 100x that if that makes life easy.
So, for these kinds of problems where you're dealing with little text files of input data, here's what you do:
malloc() yourself a fine big buffer that's big enough to slurp in the whole file with buckets and buckets of headroom
open the file, slurp the whole damn thing in with read(), and close it
record how many bytes you read in n_chars (or whatever)
do one pass through the buffer and 1) replace all the newlines with NULs and 2) record the start of each line (occurs after a newline!) into successive positions in a lines array (e.g. char **lines; lines=malloc(n_chars*sizeof(char *)): there can't be more lines than bytes!)
(optional) as you go, advance your start-of-line pointers to skip leading whitespace
(optional) as you go, overwrite trailing whitespace with NULs
keep a count of the lines as you go and save it in n_lines
remember to free() that buffer when you're done with it
Now, what do you have? You have an array of strings that are the lines of your file (optionally with each line stripped of leading and trailing whitespace) and you can do what the hell you like with it.
So what do you do?
Go through the array of lines one-by-one, like this:
for(i=0; i<n_lines; i++) {
if( '\0'==*lines[i] || '#' == *lines[i] )
continue;
// More code
}
Already you have ignored empty lines and lines that start with a "#". Your config file now has comments!
long n;
int len;
for(i=0; i<n_lines; i++) {
if( '\0'==*lines[i] || '#' == *lines[i] )
continue;
// More code
len = strlen("insert");
if( 0== strncmp(lines[i], "insert", len) ) {
n = strtol(lines[i]+len+1, &endp, 10);
// error checking
tree_insert( (int)n );
continue;
}
len = strlen("delete");
if( 0== strncmp(lines[i], "delete", len) ) {
n = strtol(lines[i]+len+1, &endp, 10);
// error checking
tree_delete( (int)n );
}
}
Now, you can probably see 10 ways of making this code better. Me too. How about a struct that contains a keywords and a function pointer to the appropriate tree function?
Other ideas? Knock yourself out!
you can call as follows.For example i have put printf but you can replace your insert/delete function instead that.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fptr;
char *charptr;
char temp[50];
fptr = fopen("bst.txt", "r");
while(fgets(temp, 50, fptr) != NULL)
{
charptr = strtok(temp, " ");
if(strcmp(charptr,"insert")==0)
{
charptr = strtok(NULL, " ");
printf("insert num %d\n",atoi(charptr));
}
else if(strcmp(charptr,"delete")==0)
{
charptr = strtok(NULL, " ");
printf("delete num %d\n",atoi(charptr));
}
}
return 0;
}
I think the best way to read formatted strings in file is using fscanf, the following example shows how to parse the file. You could store the charptr and value for further operations:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
FILE *fptr;
char charptr[50];
int value;
fptr = fopen("bst.txt", "r");
while (fscanf(fptr, "%s%d", charptr, &value) > 0)
{
printf("%s: %d\n", charptr, value);
}
return 0;
}
try this code
int main(){
FILE *fp;
char character[50];
int value;
fptr = fopen("input.txt", "r");
while (fscanf(fp, "%s%d", character, &value) > 0)
{
if(strcmp(character,"insert")==0){
insert(value);//call you function which you want value is 10 or change according to file
}
}
return 0;
}

Program not accepting all values from file

I posted a problem yesterday regarding a certain segment of my code. The aim was to basically scan in data values from a .dat file into an array, print the values whilst also counting how many values were in the file.
Sounds pretty simple, but my program only seemed to print a certain number of the values. More specifically, of a data file containing over 300000 values, it would only print the last 20000 and nothing else.
So I left it, finished the rest of my code and now it's the last part I have to sort. I've made a few changes and tried actually printing an output .dat file now so I can see what I'm getting. The code is below by the way.
Initally I assumed perhaps it was something related to the memory allocation of my array (was getting a segmentation error? when putting the whole code together) so I created an external function that counted the number of values instead (that works).
My only problem now is that it still only chooses to print 20000 values and then the rest are 0s. I was thinking perhaps it had something to do with the type but they all contain 7 dps in scientific notation. Here's a sample of some of the values:
8.4730000e+01 1.0024256e+01
8.4740000e+01 8.2065599e+00
8.4750000e+01 8.3354644e+00
8.4760000e+01 8.3379525e+00
8.4770000e+01 9.8741315e+00
8.4780000e+01 9.0966478e+00
8.4790000e+01 9.4760274e+00
8.4800000e+01 7.1199807e+00
8.4810000e+01 7.1990172e+00
Anyone see where I'm going wrong? I'm sorry for the long question, it's just been bugging me for the last day or so and no matter what I change nothing seems to help. Any kind of input would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
int count(int);
const char df[]="data_file.dat";
const char of[]="output_file.dat";
int main(int argc, char *argv[])
{
FILE *input, *output;
int i, N;
float *array;
N = count(i);
input = fopen(df, "r");
output = fopen(of, "w");
array = (float*)malloc(N*sizeof(float));
if((input != (FILE*) NULL) && (output != (FILE*) NULL))
{
for(i = 0; i < N; i++)
{
fscanf(input, "%e", &array[i]);
fprintf(output, "%d %e\n", i, array[i]);
}
fclose(input);
fclose(output);
}
else
printf("Input file could not be opened\n");
return(0);
}
int count(int i)
{
FILE *input;
input = fopen(df, "r");
int N = 0;
while (1)
{
i = fgetc(input);
if (i == EOF)
break;
++N;
}
fclose(input);
return(N);
}
Your biggest problem is that count() doesn't count float values; it counts how many characters are in the file. Then you try to loop and call fscanf() more times than there are values in the file. The first times, fscanf() finds a float value and scans it; but once the loop reaches the end of file, fscanf() will be returning an EOF status. It seems possible that fscanf() will set the float value to 0.0 when it returns EOF.
I suggest you rewrite so that you don't try to pre-count the float values. Write a loop that just repeatedly calls fscanf() until it returns an EOF result, then break out of the loop and close the files.
P.S. If you are going to write a function like count(), you should pass in the filename as an argument instead of hard-coding it. And your version of count() takes an integer argument but just ignores the value; instead, just declare a temp variable inside of count().
EDIT: Okay, here is a complete working program to solve this problem.
#include <stdio.h>
int
main(int argc, char **argv)
{
FILE *in_file, *out_file;
unsigned int i;
if (argc != 3)
{
fprintf(stderr, "Usage: this_program_name <input_file> <output_file>\n");
return 1; // error exit with status 1
}
in_file = fopen(argv[1], "r");
if (!in_file)
{
fprintf(stderr, "unable to open input file '%s'\n", argv[1]);
return 1; // error exit with status 1
}
out_file = fopen(argv[2], "w");
if (!out_file)
{
fprintf(stderr, "unable to open output file '%s'\n", argv[2]);
return 1; // error exit with status 1
}
for (i = 0; ; ++i)
{
int result;
float x;
result = fscanf(in_file, "%e", &x);
if (1 != result)
break;
fprintf(out_file, "%d %e\n", i, x);
}
return 0; // successful exit
}
Note that this version doesn't need to allocate a large array; it just needs a single temporary float variable. Maybe your program will need to store all the float values. In that case, write a count() function that uses a loop similar to the above loop, using fscanf() to count float values.
Also note that this program checks for errors after calling fopen() and fscanf().
You are allocating far more floats in memory (N) than you need because your N is the number of characters in the file, not the number of values in it.
Also, how did you determine that there are 300000 values in the file?

Resources