I have a test tomorrow and files confuse me a lot. This code I wrote stops at fscanf(f1, "%d", &n); and does not take any input in. I followed the teacher's example when coding this. Does any one have any idea why this happens? Also, is F2 completely necessary? The teacher's practice questions say to open up the file in read, read everything, keep a running total of all the wages earned, then once the reading is complete, prompt for an output filename string, open it, and write to the average value of all the earnings. I understand fprintf and fscanf to an extent, and the difference between read and write mode, however, I do not understand why F2 is necessary? He uses F2 in a similar example that used different variable names. Thanks in advance.
#include <stdio.h>
int main(){
FILE *f1;
FILE *f2;
char name[30];
char name2[30];
float wage;
float wage_total;
int n;
int SSN;
printf("What is the file name?\n");
scanf("%s", name);
f1 = fopen(name, "r");
printf("What is the file name for F2?\n");
scanf("%s", name2);
f2 = fopen(name2,"w");
int i;
wage = 0;
fscanf(f1, "%d", &n);
for(i = 0; i < n; i++){
fscanf(f1,"%d", &SSN);
fscanf(f1, "%f", &wage);
wage_total += wage;
}
fprintf(f2,"%f", wage_total);
fclose(f1);
fclose(f2);
system("pause");
return 0;
}
Teacher's Example:
#include <stdio.h>
int main() {
FILE* fp1;
FILE* fp2;
int n;
int i;
int id,len,width;char word[30],word2[30];
printf("type input fname:");
scanf("%s",word);
printf("type output fname:");
scanf("%s",word2);
fp1 = fopen(word, "r");
fp2 = fopen(word2,"w");
fscanf(fp1,"%d", &n);
for(i=0;i<n;i++)
{ fscanf(fp1,"%d%d%d", &id, &len, &width);
if ( (len*width) > 500)
printf("%d %d %d", id, len, width);
}
fclose(fp1);
fclose(fp2);
system("pause"); return 0;
}
Related
This program should ask you to add member (people) to a struct and print them on a file but after the first for loop just stop working and jump over the name part. I just found that thing that allow you to add space to a string, tried it but no success...
I tried to remove it and it work without any problem so the [^\n] make something go wrong.
What is wrong ?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
} person;
void write();
void leggi();
void trova();
int main() {
write();
}
void write() {
int i = 0;
int n = 1;
int r;
FILE *fp;
fopen_s(&fp, "index.txt", "w+");
if (fp == NULL) {
printf("Failed to open file\n");
exit(1);
}
fprintf(fp, "%d\n", i);
for (i = 0; i < n; i++) {
printf("Surame:\n");
scanf_s("%[^\n]s", person.Surname, 100);
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf_s("%s", person.Name, 100);
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf_s("%d", &person.age);
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf_s("%s", person.spec, 100);
fprintf(fp, "%s\n", person.spec);
printf("Want to enter another? 1=yes 0=no...\n");
scanf_s("%d", &r);
if (r == 1)
n = n + 1;
}
rewind(fp);
fprintf(fp, "%d\n", i);
fclose(fp);
}
There are multiple problems in your code:
you use the so called secure functions fopen_s, scanf_s etc, but you do not check the return values to detect invalid input. You should instead use standard functions, pass the appropriate arguments and check the return values.
using scanf_s is actually non portable: the scanf_s function defined in Annex K of the C Standard requires the length argument after the pointer to have size_t type, whereas the function with the same name in the Microsoft library uses type UINT, which has a different representation on 64-bit versions of their Windows OS. A classical case of the Embrace, enhance and extinguish strategy. In Standard C, one should write: scanf_s("%s", person.Name, (size_t)100) or better:
scanf_s("%s", person.Name, sizeof person.Name)
there is no need to open the output file for update with "w+", just use "w".
you rewind the stream pointer back to the beginning of file and overwrite the number of entries at the start of the file. This works as long as you have less than 10 entries, but beyond that, the number has more digits so some characters in the file will be corrupted. You could use a format with padding such as "%6d\n" which would allow for up to 1 million records without risks.
"%[^\n]s" is not a correct scanf format: you should just write "%[^\n]" or better "Â %99[^\n]" to skip initial white space and limit the input to 99 characters.
Here is a modified version:
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Staff {
char Surname[100];
char Name[100];
int age;
char spec[100];
int id;
};
void write(void);
void leggi(void);
void trova(void);
int main() {
write();
}
int flush_input(void) {
int c;
while ((c = getchar()) != EOF && c != '\n')
continue;
return c;
}
void write(void) {
int n = 0;
int r;
FILE *fp = fopen("index.txt", "w");
if (fp == NULL) {
fprintf("Failed to open file index.txt: %s\n",
strerror(errno));
exit(1);
}
fprintf(fp, "%6d\n", n);
for (;;) {
struct Staff person = { 0 };
printf("Surname:\n");
if (scanf(" %99[^\n]", person.Surname) != 1)
break;
flush_input();
fprintf(fp, "%s\t\t", person.Surname);
//loop just get over the name part
printf("Name:\n"); //after the first loop
scanf(" %99[^\n]", person.Name);
flush_input();
fprintf(fp, "%s\t", person.Name);
printf("Age:\n");
scanf("%d", &person.age);
flush_input();
fprintf(fp, "%d\t", person.age);
printf("Specialization\n");
scanf(" %99[^\n]", person.spec, 100);
flush_input();
fprintf(fp, "%s\n", person.spec);
n++;
printf("Want to enter another? 1=yes 0=no...\n");
if (scanf("%d", &r) != 1 || r != 1) {
flush_input();
break;
}
flush_input();
}
rewind(fp);
// update the entry count on 6 characters
fprintf(fp, "%6d\n", n);
fclose(fp);
}
Change the call of scanf below for entering strings by inserting a space in the beginning of the format string. For example instead of this call
scanf_s("%[^\n]s", person.Surname, 100);
(where the letter s must be removed from the format string) write
scanf_s(" %[^\n]", person.Surname, ( rsize_t )100);
^^^^^^^^
This allows to skip leading white space characters in the input buffer.
Pay attention to that changing the condition or the for loop the was as you are doing
for (i = 0; i < n; i++) {
//...
if (r == 1)
n = n + 1;
}
makes the code unclear. Instead of the for loop you could use do-while loop.
Recently I am working on a beginner projects. But I was stuck for days without knowing how to update a file. Then I found I can do it with binary files, so I started using binary files instead of normal files. But now when I write into binary files it works (I assume), but when I read from it, it gives me segmentation fault (core dumped).
Here is my structs
struct date{ // structure for dates
int mm, dd, yyyy;
};
struct {
char *initials, *name, *email, *acc_type; // unchangeable values
char id_num[11], occupation[25], address[100]; // changeable values
int phone, acc_num, balance;
struct date birth_day; // structure for birth day
} new_acc;
Here is my writing function...
void create_new(void)
{
// Allocating memory for each member in struct
new_acc.name = (char *) malloc(sizeof(new_acc.name));
new_acc.initials = (char *) malloc(sizeof(new_acc.initials));
new_acc.email = (char *) malloc(sizeof(new_acc.email));
new_acc.acc_type = (char *) malloc(sizeof(new_acc.acc_type));
system("clear");
puts("Answer the questions to make a account");
time_t l; // To generate a number
srand((unsigned) time(&l)); // Generating a random number to account number
new_acc.acc_num = l; // Assign l value to acc_num var in struct
printf("Enter your full name: ");
scanf(" %100[^\n]", new_acc.name); // scan for name, 100 characters, and also accepting spaces
printf("Enter your name with initials: ");
scanf(" %100[^\n]", new_acc.initials);
printf("Enter your birthday (mm/dd/yyyy): ");
scanf(" %d %d %d", &new_acc.birth_day.mm, &new_acc.birth_day.dd, &new_acc.birth_day.yyyy)
printf("Enter your address: ");
scanf(" %100[^\n]", new_acc.address);
printf("Enter your phone number: ");
scanf(" %10d", &new_acc.phone);
printf("Enter your id number: ");
scanf(" %10[0-9a-zA-Z]", new_acc.id_num);
printf("Enter your occupation: ");
scanf(" %50[^\n]", new_acc.occupation);
printf("Enter your email address:");
scanf(" %s", new_acc.email);
printf("Enter the account type:\n");
printf("\t#Saving\n\tFixed (1 year)\n\tFixed (2 year)\n\tFixed (3 year)\n");
scanf(" %20s", new_acc.acc_type);
printf("Enter amount to deposite: $");
scanf(" %d", &new_acc.balance);
FILE *fp;
fp = fopen("employees", "a"); // Opening file in append mode
if (fp == NULL) // If file couldn't open
puts("Cannot open a file...");
// Here, I also used while loop, but I don't know how to break it so I used for loop
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc, sizeof(new_acc), 1, fp); // writting to file
fclose(fp); // Closing file
// freeing memory after use
free(new_acc.name);
free(new_acc.initials);
free(new_acc.email);
free(new_acc.acc_type);
int out;
printf("Successfully created a account!\nYour account number is %d\n", new_acc.acc_num);
printf("Press 1 to exit, and 0 to go to main menu...");
scanf("%d", &out);
switch (out){
case 1:
exit(0);
break;
case 0:
menu();
break;
}
}
And here my reading coding snippet also
FILE *fp;
fp = fopen("employees", "r");
if (fp == NULL)
puts("Cannot open a file...");
for (int i = 0; i <= 12; ++i)
fread(&new_acc, sizeof(new_acc), 1, fp);
fclose(fp);
printf("%d\n", new_acc.acc_num); // It only prints acc_num
// After that it gives me segmentation fault
printf("%s\n", new_acc.name);
printf("%s\n", new_acc.initials);
printf("%s\n", new_acc.birth_day);
printf("%s\n", new_acc.address);
printf("%d\n", new_acc.phone);
printf("%s\n", new_acc.id_num);
printf("%s\n", new_acc.occupation);
printf("%s\n", new_acc.email);
printf("%s\n", new_acc.acc_type);
printf("%d\n", new_acc.balance);
All I don't sure correct is writing and reading bin file...
I was wrong at writing into bin file and also reading from it.
First of all I need to thank to #lulle.
As he mentioned in comments I changed char* in struct into char arrays.
char initials[80], name[250], email[100], acc_type[25];
And I also change file mode. I use ab to writing snippet. And rb in reading snippet.
And I changed my writing snippet.
Here I looped over 12 times, this wrote every record 12 time. Sad ah?
This happened because I used just address of struct &new_acc in fwrite. If you use just address of a struct in fwrite`` or fread``` it will write your whole struct. That's what happened to me. I wrote the whole struct 12 time.
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc, sizeof(new_acc), 1, fp); // writting to file
So instead of looping I changed it into this
fwrite(&new_acc, sizeof(new_acc), 1, fp); \\ This line will write whole struct
But if you want to use members of struct instead of a whole struct, you are free to use a loop. Here is a example. This example is same as above one. But remember to use i or any variable that you used in for loop when writing to file. Instead of i, if you used member name, It will also write 12 times (or as far as you are looping...)
for (int i = 0; i <= 12; ++i) // Looping 12 times
fwrite(&new_acc.[i], sizeof(new_acc.[i]), 1, fp); // writting to file
And the same thing happened to reading part (I guess...).
So I changed the code snippet like below
FILE *fp;
fp = fopen("employees", "rb");
if (fp == NULL)
puts("Cannot open a file...");
int i = 0;
while(fread(&new_acc, sizeof(new_acc), 1, fp) != 0){ /* use fread one time */
printf("%d\n", new_acc.acc_num);
printf("%s\n", new_acc.name);
printf("%s\n", new_acc.initials);
printf("%s\n", new_acc.birth_day);
printf("%s\n", new_acc.address);
printf("%d\n", new_acc.phone);
printf("%s\n", new_acc.id_num);
printf("%s\n", new_acc.occupation);
printf("%s\n", new_acc.email);
printf("%s\n", new_acc.acc_type);
printf("%d\n", new_acc.balance);
++i;
}
fclose(fp);
In C, how to store array in file(database) and how to access it in program. In this program when I enter index number for ex.2 (which contains 30), after I want to subtract the age by 5 then it shows 25 but when I want to change the index number 2 then it subtracted from 25,,,not from the given index
For example
I have store value in database(data2.txt) file
Like this..
10
20
30
40
And I want to excess or update the value(30) so what can change I can do...
#include <stdio.h>
#define PATH "/storage/emulated/0/c language/data2.txt"
int main()
{
FILE *file;
int age[], s, i;
printf("Enter the array index:");
scanf("%d", &i);
file = fopen(PATH, "r");
if (file == NULL)
{
printf("files does not exist");
return 1;
}
fscanf(file, "%d", &age[i]);
fclose(file);
printf("Enter how much age should to be subtracted:");
scanf("%d", &s);
file = fopen(PATH, "w");
age[i] = age[i] - s;
fprintf(file, "%d", age[i]);
fclose(file);
printf("%d", age[i]);
}
If you don't want to reset your file you should use "a" parametr because now when u want to update value in file you are saving only 25(like in ex) all other values are gone (But "a" appends saved value on EOF). If I get this correct you are trying to read 3 variable from file, but when u are doing it:
fscanf(file, "%d", &age[i]);
you are getting only first variable in file. If you want to get third one you need to call out this function 2 more times.
Its better to get all data into array in loop and then operate on array.
#include <stdio.h>
#define SIZE 40
int main()
{
FILE *file;
int age[SIZE], s,i, j=0;
printf("Enter the array index:");
scanf("%d", &i);
file = fopen("data.txt", "r");
if (file == NULL)
{
printf("files does not exist");
return 1;
}
while(1){ //getting all data from file to array
if(feof(file))
break;
fscanf(file, "%d", &age[j++]);
}
for(int x=0;x<j;x++)
printf("%d ",age[x]);
fclose(file);
printf("\nEnter how much age should to be subtracted:");
scanf("%d", &s);
file = fopen("data.txt", "w");
age[i] -= s;
for(int k=0;k<j;k++) //passing updated data to file
fprintf(file, "%d ", age[k]);
fclose(file);
}
The code is supposed to Accept Data,Display the entire data stored till the current execution,Modify or make changes to the already accepted data.
WHAT IM LOOKING FOR IN AN ANSWER:how to write the code for a Modify module?
how to correct the Add or accept data,Display
data so they function perfectly.
#include<stdio.h>
typedef struct
{
int select;
char lastname[25];
char firstname[25];
char address[25];
int phonenumber[25];
} addressbook;
#define ARRAYLEN 2 //The lecturer told to use this "#define ARRAYLEN 2
addressbook a[ARRAYLEN]; //but why 2?and why use ARRAYLEN 2 with define
FILE *fp;
int main() //how is it affecting my program
{
int i;
int c;
int fgetc(FILE *stream);
int fputc(int c,FILE *stream);
fp = fopen("addressbook.dat","a+");
//ADD
for( i=0; i<ARRAYLEN ; ++i)
{
printf("enter details\n");
printf("enter lastname:\n");
scanf("%s", a[i].lastname);
printf("enter firstname:\n");
scanf("%s", a[i].firstname);
printf("enter address:\n");
scanf("%s", a[i].address);
printf("enter phone number:\n");
scanf("%d", a[i].phonenumber);
fwrite(&a[i], sizeof(a), 1, fp); /* notice, array indexed */
};
fclose(fp);
//DISPLAY
fopen("addressbook.dat", "r");
for(i=0; i<ARRAYLEN; ++i)
{
fread(&a[i], sizeof(a), 1, fp );
fgetc;
printf("first name is %s",a[i].firstname);
printf("last name is %s",a[i].lastname);
printf("the address is %s",a[i].address);
printf("the phonenumber is %d",a[i].phonenumber);
};
fclose(fp);
return 0;
}
IMPORTANT NOTE: I use a windows vista os and the compiler is Turbo C++
I have been attempting to debug this program with my limited knowledge, and have compared it with other programs in which i've used the same methods to retrieve a filename for opening. However, it seems that for some odd reason the program does not recieve user input for filename, sometimes getting caught in some sort of an elusive loop.
I have used both:
scanf("%s\n", filename);
and:
gets(filename);
(i know gets is "dangerous" but this is a program that is not going to be distributed, it is an assignment in a college level class)
here is the main() function and the getssn() function (which does get user input successfully):
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define MAXS 19
#define MAXR 999
//structure defining a given client
typedef struct person {
unsigned int ssn, age, height, weight, income;
char name[MAXS+1], job[MAXS+1], religion[MAXS+1], major[MAXS+1], minor[MAXS+1], gender;
}PERSON;
//get and check for ssn validity
int getssn(){
int num;
printf("\nSSN: ");
scanf("%d", &num);
if(num<=99999999 || num>999999999){
printf("\nPlease input a valid SSN.\n");
return 0;
}
else
return num;
}
//read the specified file and check for the input ssn
int readfile(FILE *fptr, PERSON **rptr, int *count){
int v=0, i, j;
char n2[MAXS+1], b[2]=" ";
for(i=0; i<MAXR; i++){
j=i;
//read the file in chunks
if(fscanf(fptr, "%c\n%d\n%19s %19s\n%d\n%19s\n%d\n%19s\n%19s\n%d\n%d\n%19s\n\n",
&rptr[j]->gender, &rptr[j]->ssn, rptr[j]->name, n2, &rptr[j]->age,
rptr[j]->job, &rptr[j]->income, rptr[j]->major, rptr[j]->minor,
&rptr[j]->height, &rptr[j]->weight, rptr[j]->religion)==EOF)
i=MAXR;
//make first and last name one element
strcat(rptr[j]->name, b);
strcat(rptr[j]->name, n2);
//if we find a match, tell main the id
if(rptr[MAXR]->ssn==rptr[j]->ssn)
v=j;
}
//count how many clients we have
*count=j;
return v;
}
//commpare age and income
int cmpai(PERSON rec1, PERSON rec2){
int a=0, inc=0;
if(rec1.age<=(rec2.age+10) && rec1.age>=(rec2.age-10))
a=1;
if(rec1.income<=(rec2.income+10000) && rec1.income>=(rec2.income-10000))
inc=1;
if(a==1 && inc==1)
return 1;
else
return 0;
}
//compare hobbies
int cmph(PERSON rec1, PERSON rec2){
if(strcmp(rec1.major,rec2.major)==0 && strcmp(rec1.minor, rec2.minor)==0)
return 1;
else
return 0;
}
//compare weight, height, and religion
int cmpwhr(PERSON rec1, PERSON rec2){
int w=0, h=0, r=0;
double n1, n2;
n1=rec1.height;
n2=rec2.height;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
h=1;
n1=rec1.weight;
n2=rec2.weight;
if(n1<=(n2*1.1) && n1>=(n2*0.9))
w=1;
if(strcmp(rec1.religion, rec2.religion)==0)
r=1;
if(r==1 && h==1 && w==1)
return 1;
else
return 0;
}
//sort the ids in ascending order by ssn for proper output
void sort(int *A, int count){
int i, j, temp;
for(i=0; i<count; i++)
for(j=0; j<count; j++)
if(A[i+1]<A[i]){
temp=A[i];
A[i]=A[i+1];
A[i+1]=temp;
}
}
//display the possible matches in ascending ssn order
void display(int matches[], PERSON rec[], int count){
int i;
for(i=0; i<count; i++){
if(matches[i]==rec[i].ssn)
printf("%s\n", rec[i].name);
}
}
int main(){
int valid=-1, i, counter=0, *c=&counter, id[MAXR-1], totalmatches;
char filename[MAXS];
FILE *fp;
PERSON record[MAXR+1], *rp[MAXR+1];
//get a ssn from the user
do{
record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);
//get a filename
printf("Name of file of records: ");
scanf("%s", filename);
printf("%s", filename);
//open the file, if possible
if((fp=fopen(filename, "r"))==NULL)
perror(filename);
else{
printf("test");
for(i=0; i<=MAXR; i++){
rp[i]=&record[i];
id[i]=0;
}
//read the file, find the matching ssn
valid=readfile(fp, rp, c);
//check if the ssn is in the file, if not tell the user
if(valid<0){
printf("\nSSN %d is not found in file %s.\n", record[MAXR].ssn, filename);
return EXIT_FAILURE;
}
else {
//check for matches and count how many we have
for(i=0; i<counter; i++){
if(i!=valid)
if(record[valid].gender!= record[i].gender)
if(cmpai(record[valid], record[i])==1 || cmph(record[valid], record[i])==1 || cmpwhr(record[valid], record[i])==1){
id[i]=record[i].ssn;
totalmatches+=1;
}
}
//if we have matches sort them and display them, otherwise tell the user he has no match in this group
if(totalmatches>0){
sort(id, counter);
display(id, record, counter);
}
else
printf("\nNo matches.\n");
fclose(fp);
return EXIT_SUCCESS;
}
}
}
This is the current input(single quotes)/output:
run
[Switching to process 6956]
Running…
SSN: '111223333'
Name of file of records: 'clients.txt'
clients.txttest
Debugger stopped.
Program exited with status value:0.
You should your getssn() function. You need to put in a return statement.
int getssn(){
int num;
printf("\nSSN: ");
scanf("%d", &num);
return num; // You MUST put this in.
}
This will improve this code:
do{
record[MAXR].ssn=getssn();
}while(record[MAXR].ssn==0);
If you forget the return, then getssn() might return 0 forever.
You should also tell us what exact output you are seeing. You should copy all the output into your question also.
Never use any of the scanf family of functions; they don't give you nearly enough control over what happens on invalid input, and scanf("%s") is just as dangerous as gets.
But this is probably not your immediate problem. That's much more likely to be a case of trying to open a file by partial pathname when it's not in the current working directory. Try typing in the full pathname (/home/kabir/filename, C:\users\kabir\filename, sort of thing). Also, changing
printf("\nCould not open file\n");
to
perror(filename);
will give you more information when things go wrong.
It should be
scanf("%s", filename)
i.e. remove the \n
Unrelated, but you seem to have forgotten return num at the end of getssn().
Looking at your current code (8:10 pm Dublin/London time), you should use this instead:
//get a filename
printf("Name of file of records: ");
//scanf("%s", filename);
printf("scanned file: <%s>\n", filename);
//open the file, if possible
if((fp=fopen(filename, "r"))==NULL)
perror(filename);
else{
printf("test\n");
...