My fscanf outputs a large negative number - c

In this program, I am attempting to read a name and their GPA from a file. The first name is Audrey, then a white space, and then 3.6.
The second line is Oakley, then a white space, and 3.5.
int main()
{
FILE * fPtr;
FILE * fPtr2;
char x[10] = { "Oakley " };
double y;
int z;
fPtr = fopen("data.txt", "r");
if (fPtr == NULL) // open failure
puts("File open for read failed");
else
{
while (scanf("%d", &z) != EOF)
{
fscanf(fPtr, "%s", x);
fscanf(fPtr, "%lf", &y);
fprintf(stdout, "Value read = %s\n", x);
fprintf(stdout, "GPA = %lf \n", y);
}
}
fclose(fPtr);
system("pause");
return 0;
}
So, I tried this once before and it worked. In that attempt, "x[10] = Audrey" and this was the first name in the list. It worked, and the fscanf gave me her GPA. The second time, I tried scanning for Oakley and I still get Audrey, but when I remove that line I get a really large negative number.
I used fscanf because it tokenizes around whitespace, so my theory is that if the cursor gets to the proper name then it will read the next number and that will be the GPA? Right? How do I get it to search for Oakley?

You need check scanf for any errors, which could happen because the input file does not match the format you specified. Try these changes:
char user[100];
while (scanf("%s", user) == 1) {
while (fscanf(fPtr, "%s %lf", x, &y) == 2)
{
if (strcmp(user, x) == 0) {
fprintf(stdout, "GPA for %s is %lf \n", user, y);
break;
}
}
rewind(fPtr);
}
Also, fPtr2 is is uninitialized in your code, remove the line fclose(fPtr2).

Related

How to write, read and delete a file in a single script in C programming

I created a file and filled it with some entries. However, I want to read this file and show it on the screen. Also, after showing the entries, I want it to be deleted with my permission. But I am stuck at this point please help me.
EDIT: Code is updated but still couldn't figure it out how to do :/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char name[20], surname[20], city[30], country[30], gender[15];
int count = 0;
int main() {
FILE *f1;
f1 = fopen("C:\\FurkanArslan.txt", "r+");
while (count < 10) { // every step provides 5 new data, so 5*10 will provide 50 data in total.
printf("\n*Please enter required information: \n");
printf("Name :"); scanf("%s", name);
printf("Surname:"); scanf("%s", surname);
printf("Country:"); scanf("%s", country);
printf("City :"); scanf("%s", city);
printf("Gender :"); scanf("%s", gender);
fprintf(f1, " %s | %s | %s | %s | %s\n\n", name, surname, gender, city, country);
count++;
}
fclose(f1);
printf("\n<<<<<%d data has been successfully saved!>>>> \n", count * 5);
printf("-------------------------------------\n");
f1 = fopen("C:\\FurkanArslan.txt", "r");
char c, answer;
while ((c = fgetc(f1)) != EOF)
putchar(c); // In this part I displayed file on the screen.
printf("\n\n <<<< %d entries are displayed on the screen! >>>>", count * 5);
printf("\n\nWould you like to remove your file [Y/N] ?");
scanf(" %c", &answer);
if (answer == 'y' || answer == 'Y') {
remove("f1");
printf("\n\n***File successfully removed!");
}
return 0;
}
In order to show the content of a file you have to open it and read it letter by letter, after that, you can use the putchar function to output the current character
FILE *fp = fopen("path/to/file.txt","r");
char c;
while((c=fgetc(fp))!=EOF)
putchar(c);
fclose(fp);
after that to remove a file you need to use the remove function, which receives the name of the file as paramter.
remove("my_file.txt");
There are multiple issues in your code:
there is no need to make the variables and arrays global, just define them in the body of the main() function.
you should tell scanf() the maximum number of characters to store in the destination array with a length specifier in the format string (eg: "%19s") and check for conversion success.
the variable c used in the reading loop must have type int for proper detection of EOF. fgetc() returns a positive byte value if successful and the special negative value EOF at end of file.
you do not need to reopen the file after writing to it. Sine you opened it for update mode, you can just seek back to the beginning of the file with rewind(f1) or fseek(f1, 0L, SEEK_SET).
the file is open for read and update mode ("r+"): it will fail if the file does not exist. You should open it in write and update mode with "w+" to create or truncate it.
you should check that fopen succeeds at opening the file, otherwise you invoke undefined behavior passing a null stream pointer to fprintf.
to remove the file, remove() takes the filename as its argument. You must close the file before attempting to remove it.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
const char *filename = "C:\\FurkanArslan.txt";
char name[20], surname[20], city[30], country[30], gender[15];
int count = 0;
FILE *f1 = fopen(filename, "w+");
if (f1 == NULL) {
printf("Cannot open file %s.\n", filename);
return 1;
}
while (count < 10) { // every step provides 5 new data, so 5*10 will provide 50 data in total.
printf("\n*Please enter required information: \n");
printf("Name :"); if (scanf("%19s", name) != 1) break;
printf("Surname:"); if (scanf("%19s", surname) != 1) break;
printf("Country:"); if (scanf("%29s", country) != 1) break;
printf("City :"); if (scanf("%29s", city) != 1) break;
printf("Gender :"); if (scanf("%14s", gender) != 1) break;
fprintf(f1, " %s | %s | %s | %s | %s\n\n", name, surname, gender, city, country);
count++;
}
printf("\n<<<<< %d data has been successfully saved to %s! >>>>\n",
count * 5, filename);
printf("-------------------------------------\n");
rewind(f1);
int c;
while ((c = fgetc(f1)) != EOF)
putchar(c);
printf("\n\n <<<< %d entries are displayed on the screen! >>>>\n", count);
fclose(f1);
printf("\nWould you like to remove your file [Y/N] ?");
char answer;
if (scanf(" %c", &answer) == 1 && (answer == 'y' || answer == 'Y')) {
if (remove(filename)) {
printf("\n\n***Error removing file %s: %s\n",
filename, strerror(errno));
} else {
printf("\n\n***File %s successfully removed!\n", filename);
}
}
return 0;
}

Search and write data from one file to another

I need to write a C program to fetch data from one file and write it to another file, without using user defined functions. My requirements are to:
Search customer details by Name.
Store the transaction data (paid amount) in another text file.
I did the code to search by name. But its not working,
#include <stdio.h>
#include <stdlib.h>
int main () {
char name[10], nic[10], mobile[10];
char fname[10], fnic[10], fmobile[10];
char choice;
int amount;
FILE *cfptr;
printf("Enter search type - \n 1. NAME \n 2. NIC \n 3.MOBILE \n ----> ");
scanf("%c", &choice);
printf("Enter search text : ");
scanf("%s", &name);
cfptr = fopen ("customer.dat", "r");
while (!feof(cfptr)){
fscanf(cfptr, "%s %s %s", fname, fnic, fmobile);
printf("Read Name |%s|\n", fname );
printf("Read NIC |%s|\n", fnic );
printf("Read Mobile |%s|\n", fmobile );
}
fclose(cfptr);
scanf("%d", &amount);
return(0);
}
customer.dat File
Shan 100012 200202
Marsh 121213 667675
Kim 126573 663412
This code is not complete asI cant filter the single name assigning
if(name == fname)
as am getting
assignment to expression with array type error
Can any one complete me the code to search and save to another file so I can do the amount calculation part?
int Search_in_File(char *fname, char *str) {
FILE *fp;
int line_num = 1;
int find_result = 0;
char temp[512];
//gcc users
//if((fp = fopen(fname, "r")) == NULL) {
// return(-1);
//}
//Visual Studio users
if((fopen_s(&fp, fname, "r")) != NULL) {
return(-1);
}
while(fgets(temp, 512, fp) != NULL) {
if((strstr(temp, str)) != NULL) {
printf("A match found on line: %d\n", line_num);
printf("\n%s\n", temp);
find_result++;
}
line_num++;
}
if(find_result == 0) {
printf("\nSorry, couldn't find a match.\n");
}
//Close the file if still open.
if(fp) {
fclose(fp);
}
return(0);
}
few comments:
when scanning the choice, read it as an integer and not as a character.
scanf("%c", &choice); // change to scanf("%d", &choice);
single '=' is an assigment, you meant comparison which is double '=='
if(name = fname) // comparison is if(name == fname)
in order to compare string, do not use '==' operator. use strcmp or implement an equivalent of strcmp.
Thanks for the effort, As with changes, I have changed my code as below and its working. Without checking with the name, I alternately checked with the nic.
#include <stdio.h>
int main(void){
int nic, n, mobile;
char name[30];
FILE *aPtr;
aPtr = fopen("Details.txt","w");
if(aPtr == NULL){
printf("File cannot be opened");
return -1;
}
printf("Enter nic to search - ");
scanf("%d", &n);
fscanf(aPtr, "%d %-s %d", &nic, name, &mobile);
while(!feof(aPtr)){
if(nic == n){
Printf("%d %s %d \n", nic, name, mobile);
}
fscanf(aPtr, "%d %s %d", &nic, name, &mobile);
}
fclose(aPtr);
return 0;
}

Program can write to text file but crashes when trying to read back

The program runs and can successfully write to a text file, but when I try to read back from the text file I get:
"Exception thrown at 0x0F8C7071 (ucrtbased.dll) in Text Files Homework.exe: 0xC0000005: Access violation writing location 0xFFFFFFCC."
Which brings me to line 1092 in stdio.h.
The code inside the function that is supposed to read each line is:
Product temp;
char name[MAX_STRING_LEN];
char type;
double price;
int qty;
int moreData = fscanf_s(stream, "%s", temp.name, MAX_STRING_LEN - 1);
if (moreData != EOF)
{
fscanf_s(stream, "%c", temp.type);
fscanf_s(stream, "%lf", &temp.price);
fscanf_s(stream, "%d", &temp.qty);
// echo what just got read (from the file) to the console.
printf_s("%s %c %.2f %d was read \n\n", temp.name, temp.type, temp.price, temp.qty);
}
else
{
printf("Read past end of file.\n\n");
}
*pro = temp;
return moreData;
And the function that calls that function is:
FILE *stream;
Product p;
*numProducts = 0;
int err = fopen_s(&stream, fileName, "r");
if (err)
printf_s("File %s was not opened for reading. \n", fileName);
else {
printf("\n\nReading Product data from file... \n");
// Read data back from file:
int moreData = readLine(stream, &p);
while (moreData != EOF) {
printf("Number of products was %d ", *numProducts);
reportLine(p);
list[*numProducts] = p;
*numProducts = *numProducts + 1;
printf("It is now incremented to %d \n", *numProducts);
moreData = readLine(stream, &p);
}
fclose(stream);
}

read string char and int from file in c programming

student.dat file
----------------
Stu:1 abc ($) - 55 in following order (Stu: %d %s (%c) - %d)
Stu:2 pqr (^) - 82
I am trying to read this file and save highest grade details in the variable in c programming.
my code is below but is not complete!
int main(){
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
while ((fp != '\n') && (fp != EOF)) {
fscanf(fp, "%d %s %c %d", &num, name, id, &grade);
printf("Student Num: %d", num);
printf("Student Name: %s", name);
printf("Student id: %c", id);
printf("Student grade: %d", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}
}
In C, you have 2 primary ways to read line-oriented input and then parse into individual values (really 3, but we will ignore walking a pair of pointers down the string for now).
The preferred manner is to use a line-oriented input function such as fgets or POSIX getline to read an entire line into a buffer, and then parse the buffer with sscanf which can be done in a more flexible manner than a single call to fscanf.
Nonetheless, you appear dedicated to using fscanf here. The key to using fscanf successfully is to provide a format string that accounts for all characters in the line to be read, or to craft the format string to take advantage of properties of the individual format specifiers to accomplish the same thing (e.g. %s (as well as your numerical conversions) will skip leading whitespace giving you some control to deal with line-endings that would otherwise be left in the input-buffer (either the file or stdin and therefore be the next character available on a subsequent call to fscanf, which if not properly handled, will throw a wrench into your read routine.
Another mandatory step is to validate that all conversions specified were successfully completed during each read. You do that by checking the return value for fscanf which is the match count (a count of the number of successful conversions that took place). If you do not check, you cannot have any type of confidence that your values actually hold the data you think they do.
Putting that together, using your input file, and taking the filename to open as the first argument to the program (and reading by default on stdin if no filename is given), you could do something like the following:
#include <stdio.h>
int main (int argc, char **argv) {
int num =0, grade = 0, max = 0; /* initialize all variables */
char id = 0, name[35];
const char *fmt = " Stu:%d %s (%c) - %d"; /* given format string */
FILE *fp = NULL;
if (!(fp = argc > 1 ? fopen (argv[1], "r") : stdin)) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read each line and validate 4 successful conversions */
while (fscanf (fp, fmt, &num, name, &id, &grade) == 4) {
if (grade > max) max = grade;
printf ("Student Num: %d Name: %-12s id: %c grade: %d\n",
num, name, id, grade);
}
printf ("\n highest grade : %d\n\n", max);
if (fp != stdin) fclose (fp);
return 0;
}
Example Use/Output
$ ./bin/stdntread <dat/stdntread.dat
Student Num: 1 Name: abc id: $ grade: 55
Student Num: 2 Name: pqr id: ^ grade: 82
highest grade : 82
Look over the code, and especially the slight tweak to the format specifier, and let me know if you have any additional questions.
As user3386109 already hinted at: the format string "Stu: %d %s (%c) - %d" should do it. It actually doesn't, you need to add the newline, too.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int main()
{
int num, grade, ret;
char id, name[35];
int lineno = 1;
FILE *fp = NULL;
// reset errno, just in case
errno = 0;
fp = fopen("student.dat", "r");
if (fp != NULL) {
for (;;) {
ret = fscanf(fp, "Stu: %d %s (%c) - %d\n", &num, name, &id, &grade);
if (ret != 4 && ret != EOF){
fprintf(stderr,"fscanf() returned %d instead of 4 for line %d\n",ret,lineno);
// unlikely, but cheap to check, so check
if(errno != 0){
fprintf(stderr,"With error %s\n",strerror(errno));
}
exit(EXIT_FAILURE);
}
if (ret == EOF) {
// fscanf() returns EOF for end-of-file _and_ error.
// check for error first
if(errno != 0){
fprintf(stderr,"The error %s occured while reading line %d\n",strerror(errno), lineno);
exit(EXIT_FAILURE);
}
// we are done with the file at this point and can bail out graciously
break;
}
printf("Student Num: %d, ", num);
printf("Student Name: %s, ", name);
printf("Student id: %c, ", id);
printf("Student grade: %d\n", grade);
lineno++;
}
fclose(fp);
} else {
printf("Failed to open file: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
File student.dat generated with
for i in `seq 1 1 100`;do character=$(printf \\$(printf '%03o' $((`shuf -i 40-99 -n 1`))));name=$(cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w 3 | head -n 1); echo Stu:$i $name \($character\) - `shuf -i 10-99 -n 1`;done > student.dat
(Yes, that generation can be done simpler, I'm pretty sure ;-) )
First 10 lines of input (new-line is \n everywhere):
Stu:1 qim (+) - 13
Stu:2 EcF (L) - 61
Stu:3 Ko1 (Q) - 50
Stu:4 Ve7 (,) - 23
Stu:5 NiX (;) - 28
Stu:6 4O8 (C) - 73
Stu:7 00m (]) - 79
Stu:8 uiw (C) - 45
Stu:9 47k (X) - 80
Stu:10 MmJ (A) - 38
(file ends with new-line \n!)
Your while loop have incorrect condition, it'll never become false, File pointer never reaches to \n nor EOF, I had modified your code and now its working properly. Check while condition in code
int num, grade;
char id, name[35];
FILE *fp = NULL;
fp = fopen("student.dat", "r");
if (fp != NULL) {
int ret;
while((ret = fscanf(fp, "%d %s %c %d", &num, name, &id, &grade))!=EOF)
{ printf(" Student Num: %d", num);
printf(" Student Name: %s", name);
printf(" Student id: %c", id);
printf(" Student grade: %d\n", grade);
}
fclose(fp);
}else {
printf("Failed to open file\n");
}

How to get exclude null terminators when reading in a string?

This program opens a file that contains a lake's name and its volume in units of hundreds of cubic miles--separated by a space. Its output is supposed to be the lake's name followed by a number of asterisks to represent its volume to the nearest hundred cubic mile (for example, a lake that has 12.7 hundred cubic miles in volume would print 13 asterisks). However, when it reads in a name that contains a space, it reads up until the space and then prints the next string in a new line. Is there any way I can read "gross dirty lake" as one line instead of "gross\ndirty\nlake" for example? Here's what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void name_asterisks(char name[20], float vol);
main() {
FILE *fp;
fp = fopen("lakes.txt", "r");
char name[20];
float vol;
if (fp == NULL) {
printf("File does not exist.\n");
system("pause");
return 0;
}
while (fscanf(fp, "%s %f", name, &vol) != EOF) {
name_asterisks(name, vol);
}
fclose(fp);
system("pause");
}
void name_asterisks(char name[20], float vol) {
int i;
printf("%s", name);
for (i = 0; i < (int)roundf(vol); i++)
printf("*");
printf("\n");
}
"%s" is for scanning non-white-space. Code needs a different format specifier.
char buf[100];
while (fgets(buf, sizeof buf, fp) != NULL) {
if (sscanf(buf, " %19[A-Za-z ]%f", name, &vol) != 2) {
fprintf(stderr, "Unexpected data\n");
break;
}
name_asterisks(name, vol);
}
" ": Skip white-spaces.
"%19[A-Za-z ]": Scan and save up to 19 letters or spaces, append '\0'.
"%f": Skip white-spaces and save scan a float.
Note about original code: Better to check for what code wants than checking against 1 undesired result
// while (fscanf(fp, "%s %f", name, &vol) != EOF) {
while (fscanf(fp, "%s %f", name, &vol) == 2) {
sample for like as gross dirty lake 12.7\n
#include <string.h> //for strrchr
...
char line[64];//line buffer
...
while (fgets(line, sizeof line, fp)){
char *p = strrchr(line, ' ');//search last ' '
*p = '\0';
//snprintf(name, sizeof(name), "%s", line);
vol = atof(p+1);
name_asterisks(line, vol);//name_asterisks(name, vol);
}

Resources