Reputation: 9
I have a file with these contents:
Code Name Income Allow Pens Ins Depend Charity Taxable Tax Net
------------------------------------------------------------------------------------------------------------------------
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
001 Doe 50000 4000 0 500 1600 0 43900 7725 42275
I want to print a record if the input code is same as the code in the file.
This is my code:
fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t);
printf("\n");
printf(" 03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
`
but it doesn't work.
So I'm thinking about using fscanf
to read only the code and then print the line which contains that code. But how can I read the code without other contents like Name
, Income
, ... and how to read if the code has leading 0 like that?
Upvotes: 0
Views: 101
Reputation: 32596
First you cannot read the file with its header using the scanf you give because Code is incompatible with the first %d
, so you need to bypass the first 2 lines
Warning a %
is missing in your printf to print the code, so the code is considered as the string by %s
with an unspecified behavior (a crash generally)
But how can I read the code without other contents like Name, Income
Of course if you use your scanf you also read the other fields, is it a real problem ? You can also read line per line as a strings (fgets or getline) and look at the beginning if you have the expected code and in that case manage the rest of the string to extract the fields if needed etc
An other way if the content of the file is very formatted is to change the file pointer using fseek to only read the codes up to the expected one (see the proposal at the end of my answer).
how to read if the code has leading 0 like that?
I do not understand scanf read it well, this is not octal because there is 008. If the presence of the 0 at the left are important do not manage the code as a number but as a string both in the file and when the code to search is given
A code from yours reading well your input file :
#include <stdio.h>
int bypassLine(FILE * fp)
{
int c;
for (;;) {
c = fgetc(fp);
if (c == EOF)
return 0;
if (c == '\n')
return 1;
}
}
int main()
{
FILE * fp = stdin;
int code_t;
char buffer[64];
double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;
if (!bypassLine(fp) || !bypassLine(fp))
puts("too short file");
else {
while (fscanf(fp, " %3d%s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
}
}
}
Compilation and execution :
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code Name Income Allow Pens Ins Depend Charity Taxable Tax Net
------------------------------------------------------------------------------------------------------------------------
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
001 Doe 50000 4000 0 500 1600 0 43900 7725 42275
pi@raspberrypi:/tmp $ ./a.out < f
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
001 Doe 50000 4000 0 500 1600 0 43900 7725 42275
pi@raspberrypi:/tmp $
Note there is no protection against an overflow when reading the string in scanf with just %s
, if is better to use %63s
because I sized buffer 64
A little change to search for the code, still using your scanf, giving the name of the file and the expected code in argument :
#include <stdio.h>
int bypassLine(FILE * fp)
{
int c;
for (;;) {
c = fgetc(fp);
if (c == EOF)
return 0;
if (c == '\n')
return 1;
}
}
int main(int argc, char ** argv)
{
if (argc != 3)
printf("usage : %s <file> <code>\n", *argv);
else {
FILE * fp;
int code_t, expected;
char buffer[64];
double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "cannot open '%f'\n", argv[1]);
return -1;
}
if (!bypassLine(fp) || !bypassLine(fp)) {
fprintf(stderr, "too short file '%s'\n", argv[1]);
fclose(fp);
return -1;
}
if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
fprintf(stderr, "invalid code '%s'\n", argv[2]);
}
else {
while (fscanf(fp, " %3d%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", &code_t, buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 11) {
if (code_t == expected) {
printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
fclose(fp);
return 0;
}
}
fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
}
fclose(fp);
return -1;
}
}
Compilation and execution :
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ ./a.out ./f 2
code 2 not found in './f'
pi@raspberrypi:/tmp $ ./a.out ./f 8
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
pi@raspberrypi:/tmp $
An other way using fseek to move directly from code to code in the file :
#include <stdio.h>
int bypassLine(FILE * fp)
{
int c;
for (;;) {
c = fgetc(fp);
if (c == EOF)
return 0;
if (c == '\n')
return 1;
}
}
int main(int argc, char ** argv)
{
if (argc != 3)
printf("usage : %s <file> <code>\n", *argv);
else {
FILE * fp;
int code_t, expected;
char buffer[64];
double inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t;
if ((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "cannot open '%f'\n", argv[1]);
return -1;
}
if (!bypassLine(fp) || !bypassLine(fp)) {
fprintf(stderr, "too short file '%s'\n", argv[1]);
fclose(fp);
return -1;
}
if (sscanf(argv[2], "%d%c", &expected, buffer) != 1) {
fprintf(stderr, "invalid code '%s'\n", argv[2]);
}
else {
long offset = ftell(fp);
while (fscanf(fp, " %03d", &code_t) == 1) {
if (code_t == expected) {
/* extract the other fields */
if (fscanf(fp, "%63s%lf%lf%lf%lf%lf%lf%lf%lf%lf", buffer, &inc_t, &personal, &pension_t, &health_t, &depend_t, &gift_t, &taxable_t, &tax_t, &net_t) == 10) {
printf(" %03d%20s%11.0lf%9.0lf%10.0lf%8.0lf%10.0lf%11.0lf%11.0lf%10.0lf%10.0lf\n", code_t, buffer, inc_t, personal, pension_t, health_t, depend_t, gift_t, taxable_t, tax_t, net_t);
fclose(fp);
return 0;
}
else {
fprintf(stderr, "code %d found but cannot read next fields\n", code_t);
fclose(fp);
return -1;
}
}
/* the lines are supposed having all the times 114 characters newline included */
offset += 114;
if (fseek(fp, offset, SEEK_SET) == -1) {
fprintf(stderr, "error when going at offset %d of '%s'\n", offset, argv[1]);
fclose(fp);
return -1;
}
}
fprintf(stderr, "code %d not found in '%s'\n", expected, argv[1]);
}
fclose(fp);
return -1;
}
}
Compilation and execution :
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra f.c
pi@raspberrypi:/tmp $ cat f
Code Name Income Allow Pens Ins Depend Charity Taxable Tax Net
------------------------------------------------------------------------------------------------------------------------
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
001 Doe 50000 4000 0 500 1600 0 43900 7725 42275
pi@raspberrypi:/tmp $ ./a.out ./f 8
008 John 100000 4000 5000 1000 3200 1000 85800 20280 79720
pi@raspberrypi:/tmp $ ./a.out ./f 1
001 Doe 50000 4000 0 500 1600 0 43900 7725 42275
pi@raspberrypi:/tmp $ ./a.out ./f 11
code 11 not found in './f'
Upvotes: 1
Reputation: 44329
I want to print a record if the input code is same as the code in the file.
If your goal is simply to print the records (aka lines) where "Code" matches some value given by the user, your approach seems a bit too complex as there is no need for scanning all the fields.
Simply use fgets
to read the line, then check the Code value and do the print if it matches.
Something like:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
int main(int argc, char* argv[]){
if (argc != 2)
{
printf("Wrong usage...\n");
return 1;
}
int code_to_print = atoi(argv[1]);
int code_read;
FILE* fp = fopen("db.txt", "r");
if (!fp)
{
printf("File error...\n");
return 1;
}
char buf[1024];
while (fgets(buf, sizeof buf, fp))
{
if (sscanf(buf, "%d", &code_read) == 1 && code_read == code_to_print)
{
printf("%s", buf);
}
}
fclose(fp);
}
Use the program like:
./prog 8
.. how to read if the code has leading 0 like that?
If the leading zeros are important then you can't scan using %d
as that will "remove" the zeros. Instead you need to scan the Code as a word. Like:
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
int main(int argc, char* argv[]){
if (argc != 2)
{
printf("Wrong usage...\n");
return 1;
}
char code_read[4] = {0};
FILE* fp = fopen("db.txt", "r");
char buf[1024];
while (fgets(buf, sizeof buf, fp))
{
if (sscanf(buf, "%3s", code_read) == 1 && strcmp(code_read, argv[1]) == 0)
{
printf("%s", buf);
}
}
fclose(fp);
}
Use the program like:
./prog 008
Upvotes: 0