fgets and sscanf to read file into an array - c++

I am trying to implement a function that reads txt files that contain 2 double and int per line with a space as a delimiter, for example (data.txt):
3.1 2.5 1
3.4 4.5 2
.....
I implemented the function below, it takes as arguments the file name, pointers to 2 double and an int. Each pointer will be used to retrieve a column from the file. I used
fgets
to get the line and then
sscanf
to extract the three values from the line. The program crushes at run time (error: Windows has triggered a breakpont in program.exe )
... When I put a breaking point before returning from the main function the retrieved values are corrected but the program crushes when I hit continue.
To debug the function I added the following lines of code to the function ReadFile below:
if (buf[strlen(buf)-1] != '\0')
{
putchar(buf[strlen(buf)-1]); //surprisingly this line prints 1 instead of a space...
exit(1);
}
With this change the code exit without reaching the end of the function. I don't understand this because the buf variable is long enough to hold all the characters of one line from the sample file.
I would appreciate your comments to fix this problem.
Thank you.
bool ReadFile(const char* fileName, double* x, double* y, int* t, int size)
{
FILE* fp;
char buf[5000];
fp = fopen( fileName, "r" );
for( int i = 0; i < size && fgets(buf, 5000, fp) != NULL; i++)
{
buf[strlen(buf)-1] = '\0';
if (buf[strlen(buf)-2] != '\0')
{
putchar(buf[strlen(buf)-1]);//surprisingly this line prints 1 instead of a space...
exit(1);
}
sscanf(buf, "%lf %lf %d", &x[i], &y[i], &t[i]);
}
fclose(fp);
return true;
}

The problem was in the caller, the size was set to 1 instead of the number of lines in the data file.

Related

file handling: the code stops running

#include <stdio.h>
main()
{
FILE* fp;
fp = fopen("a.text", "w+");
int yes = 1, count = 0;
char tree[30];
while (yes) {
printf("enter the name of the tree\n");
scanf("%s", tree);
fprintf(fp, "%s\n", tree);
printf("do you want to enter more trees?enter 0 if no and 1 if yes\n");
scanf("%d", &yes);
count++;
}
char treeArr[count][30];
int i = 0;
for (i = 0; i < count; i++) {
fscanf(fp, "%s", &treeArr[i]);
printf("%s", treeArr[i]);
}
fclose(fp);
}
this part of the code is not working.
char treeArr[count][30];
int i = 0;
for (i = 0; i < count; i++) {
fscanf(fp, "%s", &treeArr[i]);
printf("%s", treeArr[i]);
}
I need to write the names of the trees in the file and and then put it into a string array, so that i can calculate the percentage of each tree.
this is the question. kindly provide a suitable solution.
1.As you walk along TU campus, you see lots of trees of different species on your way.
Horticulture Centre has prepared a list of every tree standing on the way from CSE Department to the Main Gate.
You have to report the percentage of each tree species.
Input
Input to your program consists of a list of the species of every tree observed by the Horticulture Department; one tree per line in .txt file. No species name exceeds 30 characters.
Output
Print the name of each tree species available in TU (sorted in order of their percentage), followed by the percentage of the population it represents.
Problem is your file pointer fp is pointing to the end of file after the while loop (where you write into the file). So the subsequent read operations (fscanf) going to return EOF immediately.
You can reset the file pointer to the beginning before reading the file:
fseek(fp, 0L, SEEK_SET);
You would have noticed this if error check your library calls (fopen, scanf, fscanf, etc).
%s specifier expexts the char* but what you are passing is char (*)[30]. Even if they point to same memory they are different types.
Remove reference operator
fscanf(fp,"%s",treeArr[i]);
^^^^^^^^^^
Also you should rewind/reset file pointer of fp file descriptor which,after loop, point to the end of file what causes that fscanf returns EOF.
fseek(fp, 0L, SEEK_SET);
// Or
rewind(fp);

Trouble with fscanf() in c programming

I am trying to read some data in a file called "data" with specific format. The data in this file is:
0 mpi_write() 100
1 mpi_write() 200
2 mpi_write() 300
4 mpi_write() 400
5 mpi_write() 1000
then code is as follow:
#include<stdlib.h>
#include<stdio.h>
typedef struct tracetype{
int pid;
char* operation;
int size;
}tracetyper;
void main(){
FILE* file1;
file1=fopen("./data","r");
if(file1==NULL){
printf("cannot open file");
exit(1);
}else{
tracetyper* t=(tracetyper*)malloc(sizeof(tracetyper));
while(feof(file1)!=EOF){
fscanf(file1,"%d %s %d\n",&t->pid,t->operation,&t->size);
printf("pid:%d,operation:%s,size:%d",t->pid,t->operation,t->size);
}
free(t);
}
fclose(file1);
}
When running with gdb, I found fscanf doesn't write data to t->pid,t->operation and t->size. Any thing wrong with my code or what? Please help me!
Your program has undefined behavior: you are reading %s data into an uninitialized char* pointer. You need to either allocate operation with malloc, or if you know the max length is, say, 20 characters, you can put a fixed string for it into the struct itself:
typedef struct tracetype{
int pid;
char operation[21]; // +1 for null terminator
int size;
} tracetyper;
When you read %s data, you should always tell fscanf the limit on the length, like this:
fscanf(file1,"%d %20s %d\n",&t->pid,t->operation,&t->size);
Finally, you should remove \n at the end of the string, and check the count of returned values instead of checking feof, like this:
for (;;) { // Infinite loop
...
if (fscanf(file1,"%d %20s %d",&t->pid,t->operation,&t->size) != 3) {
break;
}
...
}
You should loop with something like:
while ( (fscanf(file1,"%d %s %d\n",&t->pid,t->operation,&t->size)) != EOF) {
printf("pid:%d,operation:%s,size:%d",t->pid,t->operation,t->size);
}
You also need to add malloc for char array in the structure.
Also, insert a check for t as
if (t == NULL)
cleanup();

Searching for a word in a text using C, and display the info after that word

Say I have a text file like this:
User: John
Device: 12345
Date: 12/12/12
EDIT:
I have my code to successfully search for a word, and display the info after that word. However when I try to edit the code to search for 2 or 3 words and display the info after them instead of just 1 word, I cannot get it to work. I have tried adding codes into the same while loop, and creating a new while loop for the other word, but both doesn't work. There must be something I am doing wrong/not doing.
Please advice, thanks!
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char file[100];
char c[100];
printf ("Enter file name and directory:");
scanf ("%s",file);
FILE * fs = fopen (file, "r") ;
if ( fs == NULL )
{
puts ( "Cannot open source file" ) ;
exit( 1 ) ;
}
FILE * ft = fopen ( "book5.txt", "w" ) ;
if ( ft == NULL )
{
puts ( "Cannot open target file" ) ;
exit( 1 ) ;
}
while(!feof(fs)) {
char *Data;
char *Device;
char const * rc = fgets(c, 99, fs);
if(rc==NULL) { break; }
if((Data = strstr(rc, "Date:"))!= NULL)
printf(Data+5);
if((Data = strstr(rc, "Device:"))!=NULL)
printf(Device+6);
}
fclose ( fs ) ;
fclose ( ft ) ;
return 0;
}
Ok, hope I can clear it this time. Sorry if I get confusing sometimes but my english is not the best.
I'll explain the implementation inside comments:
#define BUFFSIZE 1024
int main()....
char buff[BUFFSIZE];
char delims[] = " "; /*Where your strtok will split the string*/
char *result = NULL;
char *device; /*To save your device - in your example: 12345*/
char *date; /*To save the date*/
int stop = 0;
fp = fopen("yourFile", "r");
while( fgets(buff, BUFFSIZE,fp) != NULL ) /*This returns null when the file is over*/
{
result = strtok( buff, delims ); /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/
while(result != NULL){ /*Strtok returns null when finishes reading the given string*/
if(strcmp(result,"Device")==0){ /*strcmp returns 0 if the strings are equal*/
result = strtok(NULL, delims); /*this one gets the 12345*/
device = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
strcpy(device, result); /*Now, device is "12345"*/
}
/*Here you do the same but for the string 'Date'*/
if(strcmp(result,"Date")==0){ /*strcmp returns 0 if the strings are equal*/
result = strtok(NULL, delims); /*this one gets the 12345*/
date = (char*)malloc((strlen(result)+1)*sizeof(char)); /*Alocate the right amount of memory for the variable device*/
strcpy(date, result); /*Now, device is "12/12/12"*/
}
/*And you can repeat the if statement for every string you're looking for*/
result = strtok(NULL,delims); /*Get the next token*/
}
}
/*No strtok necessary here */
...
Hope this helps.
fgetc returns an integer value, which is character, promoted to int.
I suppose you meant fgets which reads a whole line, but you need to reserve memory for it, for example:
#define BUF 100
...
char c[BUF];
fgets(c, BUF, fs);
Some helpful links.
There are a couple of problems in your code: basically it never compiled.
Here is a version with small cleanups - which at least compiles:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char file[100];
char c[100];
printf ("Enter file name and directory:");
scanf ("%s",file);
FILE * fs = fopen (file, "r") ;
if ( fs == NULL ) {
puts( "Cannot open source file" ) ;
exit(1 ) ;
}
while(!feof(fs)) {
char *Data;
char const * rc = fgets(c, 99, fs);
if(rc==NULL) { break; }
if((Data = strstr(rc, "Device"))!= NULL)
printf("%s", Data);
}
fclose ( fs ) ;
return 0;
}
Problems I found:
Missing include for exit()
Missing parameter for exit()
Missing while loop to run through the whole input file.
The output file was never used.
Missing return value of 'main'
Fancy Data[5]
Changed fgetc() to fgets()
I only did minimal edits - it's not perfect at all....
IMHO I would go for C++: many things are much simpler there.
If printf() isn't a hard/fast rule, and the input requirements are really this simple, I'd prefer a state-machine and a constant-memory input:
int c, x = 0; // c is character, x is state
while(EOF!=(c=getchar())){ // scanner entry point
if(c == '\n') x=0; // newline resets scanner
else if(x == -1) continue; // -1 is invalid state
else if (x < 7 && c=="Device:"[x])x++; // advance state
else if (x == 7 && isspace(c)) continue; // skip leading/trailing whitespace
else if (x == 7) putchar(c); // successful terminator (exits at \n)
else x = -1; // otherwise move to invalid state
}
I would do that with two loops: one to get a line from the file and other to make tokens from the line read.
something like:
#define BUFFSIZE 1024
int main()....
char buff[BUFFSIZE];
char delims[] = " ";
char *result = NULL;
int stop = 0;
fp = fopen("yourFile", "r");
while( fgets(buff, BUFFSIZE,fp) != NULL ) /*This returns null when the file is over*/
{
result = strtok( buff, delims ); /*You just need to do reference to buff here, after this, strtok uses delims to know where to do the next token*/
while(result != NULL){ /*Strtok returns null when finishes reading the given string*/
if(strcmp(result,"Device")==0){ /*strcmp returns 0 if the strings are equal*/
stop = 1; /*Update the flag*/
break; /*Is now possible to break the loop*/
}
result = strtok(NULL,delims); /*Get the next token*/
}
if(stop == 1) break; /*This uses the inside flag to stop the outer loop*/
}
result = strtok(NULL, delims); /*Result, now, has the string you want: 12345 */
...
this code is not very accurate and I didn't tested it, but thats how I would try to do it.
Hope this helps.
My suggestion is to use fread to read all the file.You could read it character by character, but IMHO (a personal taste here) it's simpler to get a string containing all the characters and then manipulating it.
This is the function prototype:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
It returns the number of elements read.
For example:
char buffer[100];
size_t n= fread(buffer, 1,100, fs);
Then you can manipulate the string and divide it in tokens.
EDIT
There is a nice reference with also an example of how dividing a string into tokens here:
http://www.cplusplus.com/reference/cstring/strtok/
c and Data are char-pointers, pointers to (the start of a list of) character value(s).
fgetc's prototype is int fgetc ( FILE * stream ); meaning that it returns (one) integer value (an integer is convertible to a single char value).
If fgetc's prototype would've been int * fgetc ( FILE * stream ); the warning wouldn't have appeared.
#Dave Wang
My answer was too big to be a comment. So here it goes:
You're welcome. Glad to help.
If you make a new loop, the fgets won't work because you are already 'down' in the text file. Imagine something like a pointer to the file, every time you 'fget it' from a file pointer, you advance that pointer. You have functions to reload the file or push that pointer up, but it is not efficient, you've already passed by the information you want, there must be a way to know when.
If you're using my implementation, that is done by using another string compare inside the loop:
if(strcmp(result,"date") == 0)
If you enter this if, you know that the next value in result token with strtok is the actual date.
Since you have now two conditions to be tested, you can't break the outer loop before having both of them. This can be accomplished by two ways:
1-Instead of a flag, use a counter that is incremented everytime you want an information. If that counter has the same number of information you want, you can break the outer loop.
2-Don't break the outer loop at all! :)
But in both, since there are 2 conditions, make sure you treat them inside the ifs so you know that you dealing with the right information.
Hope this helps. Anything, just ask.

Can't write an integer into a binary file C++

This is basically the part of the code that i used to store the entire file, and works well ... but when i tryed to store a integer bigger than 120 or something like that the program writes seems like a bunch of trash and not the integer that i want. Any tips ? I am an college student and dont have a clue whats happening.
int* temp
temp = (int*) malloc (sizeof(int));
*temp = atoi( it->valor[i].c_str() );
//Writes the integer in 4 bytes
fwrite(temp, sizeof (int), 1, arq);
if( ferror(arq) ){
printf("\n\n Error \n\n");
exit(1);
}
free(temp);
I've already checked the atoi part and it really returns the number that I want to write.
I changed and added some code and it works fine:
#include <iostream>
using namespace std;
int main()
{
int* temp;
FILE *file;
file = fopen("file.bin" , "rb+"); // Opening the file using rb+ for writing
// and reading binary data
temp = (int*) malloc (sizeof(int));
*temp = atoi( "1013" ); // replace "1013" with your string
//Writes the integer in 4 bytes
fwrite(temp, sizeof (int), 1, file);
if( ferror(file) ){
printf("\n\n Error \n\n");
exit(1);
}
free(temp);
}
Make sure you are opening the file with the correct parameters, and that the string you give to atoi(str) is correct.
I checked the binary file using hex editor, after inputting the number 1013.
int i = atoi("123");
std::ofstream file("filename", std::ios::bin);
file.write(reinterpret_cast<char*>(&i), sizeof(i));
Do not use pointers here.
Never use malloc / free in C++.
Use C++ file streams, not C streams.

Access violation error with the new command

I am working on an assignment for my GUI programming class, in which we are to make a windows program that displays the contents of a file in hexadecimal. I have a class that holds the text and creates the hex in string format.
I'm attempting to create an array of character arrays to store each line for output. However, when I use new to create the array of character pointers, I get an access violation error.
I've done some searching, but haven't had any luck finding the answer.
The class has these member variables:
char* fileText;
char** Lines;
int numChars;
int numLines;
bool fileCopied;
My constructor:
Text::Text(char* fileName){ //load and copy file.
fileText = NULL;
Lines = NULL;
fileCopied = ExtractText(fileName);
if ( fileCopied ) {
CreateHex();
}//endif
}//end constructor
ExtractText loads the file given to the constructor, and copies it into a large string.
bool Text::ExtractText(char fileName[]){
char buffer = '/0'; //buffer for text transfer
numChars = 0; //initialize numLines
ifstream fin( fileName, ios::in|ios::out ); //load file stream
if ( !fin ) { //return false if the file fails to load
return false;
}//endif
while ( !fin.eof() ) { //count the lines in the file
fin.get(buffer);
numChars++;
}//endwh
fileText = new char[numLines]; //create an array of strings, one for each line in the file.
fin.clear(); //clear the eof flag
fin.seekg(0, ios::beg); //move the get pointer back to the start of the file.
for ( int i = 0; i < numChars; i++ ) { //copy the text from the file into the string array.
fin.get(fileText[i]);
}//endfr
fileText[numChars-1] = '\0';
fin.close();
numLines = (numChars % 16 == 0) ? (numChars/16) : (numChars/16 + 1);
return true;
}//end fun ExtractText
Then comes the problem code. In the CreateHex function, the first line is where try to create the array of character pointers.
void Text::CreateHex(){
Lines = new char*[numLines];
As soon as the program runs that line of code, that's when I get the access violation. I'm not really sure what the problem is, because I've used that exact same method before in a previous program. The only difference was the name of pointer. I'm using Borland C++ 5.02 if that makes any difference. It's not my first choice in compilers, but its what our teacher wants us to use.
When you execute the line
fileText = new char[numLines]
The variable numLines has not yet been initialized. As a member variable, it's initialized to 0, so you are allocating an empty array for fileText.