C reading in from a vertical line character delimited file - c++

new to C and trying to read in a text file, "stocks", delimited with vertical line '|' characters. Aim is to open the file which is has a string and float value on each line, in the format:
TOM|149.62
JIM|23.25
I have read other posts about commas, colon and tab delimited files, but the "scanset" suggestion applied here as a [^|] between the %s and %f doesn't seem to work. I seem to have managed to store the first character of the string at least now, but the float value saved is nonsense. This will later be writing to the arrays declared after the file but the basic case of displaying the string and float value for each line means I can continue on my own. Appreciate any help you can give me.
#include <iostream>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
// TOM|149.62
// JIM|23.25
int main()
{
FILE *stocks;
char *stock_Tickers[100];
float stock_Prices[100];
if ((stocks = fopen("Stocks.txt", "r")) == NULL)
{
fprintf(stderr, "Error opening file.\n");
exit(1);
}
char tempchar;
float tempfloat;
for (int i = 0; i < sizeof (stock_Tickers); i++)
{
if (feof(stocks))
{
break;
}
fscanf(stocks, "%s[^|]%f\n",&tempchar,&tempfloat);
cout << tempchar << " " << tempfloat;
cin.get();
}
return 0;
}
Update: #Michel Billaud Apologies, but I have one last error here. Your method worked perfectly, but when I try it on this slight variant it starts printing rubbish on the last floating point and breaks on subsequent loops. Looked at the local variables and the last array just isn't updating. I think it has to do with the new line, as when I change the float for an integer it still doesn't work. Can you see what I might be doing wrong as it seems the same format to me? Format this time is Ryan|B|IBM|100|176.10. All files are read in after this...Thanks.
FILE *trades;
// Ryan|B|IBM|100|176.10
// Ryan|S|IBM|50|177.10
char trade_User[100][20];
char trade_Type[100];
char trade_Tickers[100][4];
int trade_Quantity[100];
float trade_Prices[100];
int trade_Count = 0;
if ((trades = fopen("Trades.txt","r")) == NULL)
{
fprintf(stderr, "Error opening file.\n");
exit(1);
}
for (int i = 0; i < sizeof(trade_Tickers); i++)
{
if (feof(trades))
{
break;
}
fscanf(trades, "%19[^|]|%1[^|]|%4[^|]|%d[^|]|%f\n",
&trade_User[i], &trade_Type[i], &trade_Tickers[i], &trade_Quantity[i], &trade_Prices[i]);
printf("%s %c %s %d %f\n",
trade_User[i], trade_Type[i], trade_Tickers[i], trade_Quantity[i], trade_Prices[i]);
trade_Count++;
}

Hint: when trying to use a problematic feature, do it in a small separate program. So you won't take the risk to draw wrong conclusions because of another unrelated issue.
// just playing with |-separated fields
#include <stdio.h>
int main(int argc, char **argv)
{
char line[]="TOM|1234.56";
char name[20];
float value;
sscanf(line, "%[^|]|%f", name, &value);
printf("name = %s, value = %f\n", name, value);
return 0;
}
By the way: seems you're using the C++ compiler (because of "using namespace std").

Related

C File Handling - Trouble using Strings with Char

Good day, I'm having some trouble with my code. I just started with file handling last week and I'm currently stuck with adding Strings to the program. I would like to add the names in the main program from the file, but I've tried pretty much everything. Any help would be highly appreciated. Also, this is my first time on Stack Overflow, so sorry if I missed posting any information.
The picture includes the Input.txt file as well as the current output. I added console output to test the problem and it seems to have something to do with the characters. I've tried using String itself, but that was still a fail. Also, I'm not allowed to use the C++ way of file handling (if that makes sense). [I am allowed to use C++ though] - Doing this whole program for practice for my upcoming exams.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
using namespace std;
int ReadFile(char*,int*,double*);
int main()
{
char names[128];
int ages[128];
double salaries[128];
int size = ReadFile(names, ages, salaries);
for(int i = 0; i < size; i++)
{
printf("My name is %s, and I am %d years old. My salary is $%.2lf\n", *(names+i), *(ages+i), *(salaries+i));
}
return 0;
}
int ReadFile(char *namesArr, int *ageArr, double *salaryArr)
{
FILE *IN = fopen("Input.txt", "r");
int i = 0;
if(IN == NULL)
{
cout << "Error! Can't open file.";
exit(1);
}
else
{
char name[20];
int age = 0;
double salary = 0.00;
while(fscanf(IN, " %c,%d,%lf", &name, &age, &salary) != EOF)
{
*(namesArr + i) = *name;
*(ageArr + i) = age;
*(salaryArr + i) = salary;
cout << *(namesArr+i) << " ";
i++;
}
}
fclose(IN);
return i;
}
Input.txt:
Kazu,21,2250.00 Anonymous,34,3500.25 John,31,2750.00 Paul,25,3125.25
Jin,19,1750.00
Save time, enable all compiler warnings
My name is %s --> My name is %c
If you want to read in the name, and not just the first letter, many more changes needed too such as:
char name[20];
int age = 0;
double salary = 0.00;
while(fscanf(IN, " %19[A-Za-z'] ,%d ,%lf", &name, &age, &salary) == 3)
{
*(namesArr + i) = *name; // This only copies the first `char`
strcpy(TBD, name); // Need something like this.
// TBD is a pointer to an `char` array
*(ageArr + i) = age;
*(salaryArr + i) = salary;
cout << TBD << " ";
i++;
}

using scanf and printf makes the program infinite loop but by replacing with cin and cout works ok

My problem was to take the inputs until user input the test value 0 and the problem is to be solved only by c language, my code below becomes infinite loop by using scanf and printf but the same code if written in C++ it works fine with no problem, Can you help me with my C program what i am missing.
#include <stdio.h>
#include <stdlib.h>
int main() {
int click,test=1,count=0;
char vote;
scanf("%d",&test);
while(test){
int i=0;
for(int i=0;i<test;i++){
scanf("%c",&vote);
scanf("%d",&click);
printf("%c %d hi \n",vote,click);
}
scanf("%d",&test);
}
//printf("%d\n",count);
return 0;
}
my test case was
2
P 1
P 2
2
P 2
M -2
0
In c++ my output comes exactly like test case but in c language its TLE or output limit exceed
When dealing with C you should always check return values of runtime functions, it is the best way to avoid getting errors like the one you have.
scanf returns the number of items that it managed to parse or 0 if it failed.
personally i prefer to use fgets() to read from the stdin and then sscanf to parse the buffer, that way you have (IMHO) a better control of what comes into the program as opposed to obscure scanf formatting. it is easy to do mistakes with scanf because one tends to forget that all input is buffered and scanf reads from that buffer.
E.g. (ocular compiled only)
int click = 0;
int test = 0;
char buffer[128];
char vote = 0;
do
{
if ( fgets(buffer,sizeof(buffer),stdin) != NULL)
{
// read number of tests
if (sscanf(buffer, "%d", &test) == 1)
{
for(int i=0; i < test; ++i)
{
if (fgets(buffer, sizeof(buffer), stdin) != NULL)
{
if (sscanf( buffer, "%c %d", &vote, &click) == 2)
{
printf( "%c %d hi \n", vote, click );
}
else
{
fprintf(stderr, "Invalid format encountered\n");
}
}
}
}
}
}
while (test);
The %c conversion specifier poses problem with leading white spaces as it won't automatically skip them. Since you're receiving inputs in loop, one way to mitigate it is via putting extra space before %c.
scanf(" %c", &vote);

Cannot resolve EXC_BAD_ACCESS (code=EXC_I386_GBFLT)

I'm very new at C++, maintaining my M.Sc on Information Systems. I have my first C++ homework announced and have been working on it for a couple of days. The aim of the code is simply to read info from a text file and print it on screen, then make calculation on some of it and print results to a new text file. However when I build, it gives the error:
EXC_BAD_ACCESS (code=EXC_I386_GBFLT)
in the first fscanf in readInfo function.
I know the code I wrote is not completely efficient but I just want it to print on screen and on output file correctly. I would really appreciate if anyone help me to resolve this error. I am about to freak out...
#include <stdio.h>
typedef struct {
char id[10];
char name[40];
float midterm;
float final;
int attendance;
}Student;
void readInfo(Student studentList[], int *count)
{
FILE *fin=fopen("scores.txt","r");
char surname = '\0';
*count=0;
while(!feof(fin))
{
fscanf(fin,"%c %c %c %f %f %d",studentList[*count].id, studentList[*count].name, &surname, &studentList[*count].midterm, &studentList[*count].final, &studentList[*count].attendance);
strcpy(studentList[*count].name, studentList[*count].name);
strcat(studentList[*count].name, " ");
strcat(studentList[*count].name, &surname);
*count++;
}fclose(fin);
printf("%-7s%17s %5.1f %5.1f %-2d\n", studentList[*count].id, studentList[*count].name, studentList[*count].midterm, studentList[*count].final, studentList[*count].attendance);
}
float studentScore(float midterm, float final, int attendance)
{
float score;
int maxAttend=0;
char id[10];
char name[40];
char surname[40];
FILE *fin=fopen("scores.txt","r");
while(!feof(fin))
{
fscanf(fin,"%c %c %c %f %f %d",id, name, surname, &midterm, &final, &attendance);
if(attendance>maxAttend)
maxAttend=attendance;
}fclose(fin);
score=midterm*0.3+final*0.5+(maxAttend/20)*attendance;
return score;
}
float avgScore(Student studentList[])
{
float average;
int count;
int totalScore=0;
readInfo(studentList, &count);
for(int i=0; i<=count; i++)
{
totalScore+=studentScore(studentList[count].midterm, studentList[count].final, studentList[count].attendance);
}
average=totalScore/count;
return average;
}
void courseGradeOutput(Student studentList[])
{
FILE *fout=fopen("output.txt","w");
int count;
int pass=0;
float score;
char letterGrade[2];
float avg;
fprintf(fout,"\tId\tName, Surname = (Score, Letter)\n");
readInfo(studentList, &count);
for(int i=0; i<=count; i++)
{
score=studentScore(studentList[i].midterm, studentList[i].final, studentList[i].attendance);
if(score>=0 && score<=49)
{ letterGrade[0]={'F'};
letterGrade[1]={'F'};}
else if (score>=50 && score<=59)
{letterGrade[0]={'F'};
letterGrade[1]={'D'};}
else if (score>=60 && score<=64)
{letterGrade[0]={'D'};
letterGrade[1]={'D'};}
else if (score>=65 && score<=69)
{letterGrade[0]={'D'};
letterGrade[1]={'C'};}
else if (score>=70 && score<=74)
{letterGrade[0]={'C'};
letterGrade[1]={'C'};}
else if (score>=75 && score<=79)
{letterGrade[0]={'C'};
letterGrade[1]={'B'};}
else if (score>=80 && score<=84)
{letterGrade[0]={'B'};
letterGrade[1]={'B'};}
else if (score>=85 && score<=89)
{letterGrade[0]={'B'};
letterGrade[1]={'A'};}
else if (score>=90 && score<=100)
{letterGrade[0]={'A'};
letterGrade[1]={'A'};}
if(score>=60)
pass++;
fprintf(fout,"%7s %16s = ( %4.1f, %6s\n)", studentList[i].id, studentList[i].name, score, letterGrade);
}
avg=avgScore(studentList);
fprintf(fout,"\nSome statistics:\n\nClass Avg Score: %5.2f \n #Students: %11d \n #Passed Students: %4d \n #Failed Students: %4d",avg,count,pass,(count-pass));
fclose(fout);
}
int main()
{ Student studentList[100];
int count;
readInfo(studentList, &count);
courseGradeOutput(studentList);
}
Screenshot
The crash is most likely caused by either fscanf followed by strcpy and/or by your increment of count inside readInfo.
You write *count++, but this is equivalent to
count = count + 1;
*(count-1);
What you want is (*count)++.
The fscanf scans characters %c where you want to scan strings %s (for id and name). You also want to scan surname as a string, probably, but then you need to change surname to be a character array:
char surname[30];
*count=0;
while(!feof(fin))
{
fscanf(fin,"%s %s %s %f %f %d",studentList[*count].id, studentList[*count].name, surname, &studentList[*count].midterm, &studentList[*count].final, &studentList[*count].attendance);
strcat(studentList[*count].name, " ");
strcat(studentList[*count].name, surname);
(*count)++;
}
fclose(fin);
I also removed the first strcpy as you were copying from a buffer to itself, which is not allowed.
I haven't checked the other functions thoroughly, but I do notice that you do not use the result from your readInfo called from main when you do courseGradeOutput: this function calls readInfo again. You could modify it to take the read student records and the count, so you don't have to read the file again.
You might also want to improve scanf a bit to pass a width, such as %29s for name, to avoid overflowing the buffer when the name inside the file is too long; and the same for the other strings you scan. You should then also look at the return value of fscanf and only use the things you scanned when it succeeded in scanning every argument.

fill Arry function not storing characters and outputting symbols

I wrote this program for class. I have a problem with displaying what in the arry
all i get is symbols instead of a character even though i filled them with char from a file provided by the professor. please help me figure out what is the problem here i need it for tomorrow
// This program grades multiple choice exams1. Each exam consists of 20 questions.
//Each question has one of four possible answers: A, B, C, or D.
#include <stdio.h>
#include<stdlib.h>
#include <math.h>
const int maxsize = 20;
int fillArry (FILE *fi,char arry[],const int maxsize);
double gradeExam (char arry[], char studarry[],const int maxsize);
void desplayResults (double right);
int main ()
{
char arry[maxsize];
char studarry[maxsize];
int num,num1,i,right;
FILE *fi,*sd;
fi = fopen ("CorrectAnswers.txt","r");
if ( fi == NULL )
{
printf( "Error opening input file.\n\n" );
exit(1);
}
sd = fopen ("StudentAnswers.txt", "r");
if ( sd == NULL )
{
printf( "Error opening input file.\n\n" );
exit(1);
}
num = fillArry (fi,arry,maxsize);
num1 = fillArry (sd,studarry,maxsize);
for (i=0;i<maxsize;i++)
{
printf("%c\n",arry);
}
for (i=0;i<maxsize;i++)
{
printf("%c\n",studarry);
}
right = gradeExam (arry, studarry ,maxsize);
printf("you got %i right\n", right);
desplayResults (right);
return 0;
}
int fillArry (FILE *fi,char arry[],const int maxsize)
{
int u = 0;
while((fscanf(fi,"%c",&arry)==1 )&& u< maxsize)
{
u++;
}
return u;
}
double gradeExam (char arry[], char studarry[],const int maxsize)
{
int i, right=0, wrong=0;
for (i=1;i<=maxsize;i++)
{
if (arry[i]==studarry[i])
right++;
else
{
printf ("question number %i :%c is wrong, the correct answer is %c\n\n",i,studarry,arry);
wrong++;
}
}
printf("\nnumber of wrong answers: %i\n",wrong);
return right;
}
void desplayResults (double right)
{
double res;
res = (right/20)*100;
printf("You got %s %.2lf on the exam\n","%",res);
if (res<70)
printf ("You failed the exam\n");
else
printf ("You passed the exam\n");
}
The problem is with your fscanf statement. Try this out.
fscanf(fi,"%s",arry)
Also, for displaying the array contents, you have to do it like this :
for(i=0; i<maxsize; i++)
{
printf("%c",arry[i]);
}
EDIT1 : I have verified the same thing at my end and it is working. Please check the contents of the file CorrectAnswers.txt.
EDIT2 : I got the problem. It is in your print statement :
printf ("question number %i :%c is wrong, the correct answer is %c\n\n",i,studarry,arry);
Please correct it to :
printf ("question number %i :%c is wrong, the correct answer is %c\n\n",i,studarry[i],arry[i]);

How to read a multiple line input from command line in c or C++?

For Example:
If I need to read a multiple line input like(and I dont know How many lines would be there!!):
1 20
2 31
3 41
I am using something like
int main()
{
string line;
while(getline(cin,line) != NULL)
{
// some code
// some code
}
}
Now the program never stops- i.e always it expects some input. How do i beak the loop when there are no more input lines ?
Just test the variable line for empty each time you read a line. If the use presses enter with no other data, then line will be empty.
#include <iostream>
#include <string>
using std::cin;
using std::getline;
using std::string;
int main(int argc, char *argv[]) {
string line;
while (true) {
getline(cin, line);
if (line.empty()) {
break;
}
// some code
}
return 0;
}
Note that the use of scanf directly on stdin is not very safe. For example, entering anything that can't be parsed as a number will make the loop hang. Here's a more robust implementation that reads whole lines first and then tries to parse the numbers from it.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char * line = NULL;
size_t sz = 0;
while(!feof(stdin)) {
ssize_t ln = getline(& line, & sz, stdin);
if(ln > 0) {
int x, y;
if(sscanf(line, "%d %d", & x, & y) == 2)
printf("x = %i, y = %i\n", x, y);
else
puts("invalid input");
}
}
return EXIT_SUCCESS;
}
Just insert a special end-of-input command, and parse the rest line-by-line. You can't automatically detect end-of-input, because there's no way to know if the user is genuinely finished inputting or just browsing or speaking or whatever- it's a totally system-external circumstance.
On linux - C-d (or Ctrl+D) outputs the EOF character, which will terminate your loop.
It's much easier to do something like...
~ $ cat sample.input | my_cool_program
output will be displayed here.
while (true)
{
long value1;
long value2;
int nofValuesRead;
nofValuesRead = scanf("%ld %ld\n",&value1,&value2);
if (nofValuesRead==0) break;
if (nofValuesRead>=1)
{
// Process value1
}
if (nofValuesRead>=2)
{
// Process value2
}
}