This code works for me — I've made it into what is close to an MCVE (Minimal, Complete, Verifiable Example:
#include <stdio.h>
static void choice3(FILE *infile, int id)
{
int animalID = -37;
char animalName[20];
char animalType[20];
char animalSize;
int animalAge;
while (fscanf(infile, "%d , %19[^,] , %19[^,] , %c , %d",
&animalID, animalName, animalType, &animalSize, &animalAge) == 5)
{
printf("Read: %d: %s, %s, %c, %d\n",
animalID, animalName, animalType, animalSize, animalAge);
if (animalID == id)
{
printf("Animal Found: %d: %s, %s, %c, %d\n",
animalID, animalName, animalType, animalSize, animalAge);
}
}
if (feof(infile))
printf("EOF\n");
else
printf("Format error\n");
}
int main(void)
{
choice3(stdin, 3);
return 0;
}
It hard-wires the desired animal ID at 3, and reads from standard input, so I ran the program (csv47
) on your data file (data
) and got:
$ ./csv47 < data
Read: 1: Allegra, Pseudois nayaur, S, 5
Read: 2: unknown, Ailurus fulgens, X, 10
Read: 3: Athena, Moschus fuscus, X, 2
Animal Found: 3: Athena, Moschus fuscus, X, 2
EOF
$
Not all the spaces in the fscanf()
format string are necessary; none is harmful. Note that the code checks for the correct number of fields and exits the loop. Note that the data is printed so that it clear what was read — that's a basic debugging technique. The test after the loop is a correct use of feof()
; using feof()
to control the loop is almost invariably wrong.
You would do better to use a line reading function (fgets()
or POSIX getline()
, for example) to read a line of data, and then you could print, scan, rescan, report on the line that caused trouble. This generally leads to better error reporting, if only because you have the entire line available, rather than whatever fragment is left over after fscanf()
has read some but not all the fields.
Note too that this won't cope with fields enclosed in double quotes containing commas, or some other standard CSV conventions. Those really require library code to handle the reading.
Finally, this edit concerns itself only with reading the data into the local variables and avoiding 'infinite loops'. For a discussion of storage, see David C. Rankin's answer.
animals.dat
from Google Drive
The animals.dat
file that was available from Google Drive at 2017-12-03 19:00:00 -08:00 was a binary file written with little-endian integers (Intel machines) using the 60-byte structure outlined in the question (and used in the printing code below). Just in case it isn't available, the following is the output from xxd -i animals.dat
— a C array definition that contains the same data:
unsigned char animals_dat[] = {
0x01, 0x00, 0x41, 0x62, 0x69, 0x67, 0x61, 0x69, 0x6c, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x43, 0x61,
0x70, 0x72, 0x69, 0x63, 0x6f, 0x72, 0x6e, 0x69, 0x73, 0x20, 0x73, 0x75,
0x6d, 0x61, 0x74, 0x72, 0x61, 0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x53, 0x08, 0x00,
0x02, 0x00, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x4f, 0x72,
0x79, 0x78, 0x20, 0x6c, 0x65, 0x75, 0x63, 0x6f, 0x72, 0x79, 0x78, 0x00,
0x6d, 0x61, 0x74, 0x72, 0x61, 0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4d, 0x0c, 0x00,
0x03, 0x00, 0x41, 0x64, 0x72, 0x69, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x43, 0x65,
0x70, 0x68, 0x61, 0x6c, 0x6f, 0x70, 0x68, 0x75, 0x73, 0x20, 0x64, 0x6f,
0x72, 0x73, 0x61, 0x6c, 0x69, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4c, 0x10, 0x00,
0x04, 0x00, 0x41, 0x68, 0x6d, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x4e, 0x61,
0x65, 0x6d, 0x6f, 0x72, 0x68, 0x65, 0x64, 0x75, 0x73, 0x20, 0x67, 0x72,
0x69, 0x73, 0x65, 0x75, 0x73, 0x00, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4c, 0x0a, 0x00,
0x05, 0x00, 0x41, 0x69, 0x64, 0x61, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x4e, 0x61,
0x65, 0x6d, 0x6f, 0x72, 0x68, 0x65, 0x64, 0x75, 0x73, 0x20, 0x63, 0x61,
0x75, 0x64, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x58, 0x09, 0x00,
0x06, 0x00, 0x41, 0x6c, 0x6c, 0x65, 0x67, 0x72, 0x61, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x50, 0x73,
0x65, 0x75, 0x64, 0x6f, 0x69, 0x73, 0x20, 0x6e, 0x61, 0x79, 0x61, 0x75,
0x72, 0x00, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x53, 0x05, 0x00,
0x07, 0x00, 0x41, 0x6d, 0x65, 0x6c, 0x61, 0x00, 0x61, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x43, 0x65,
0x72, 0x64, 0x6f, 0x63, 0x79, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x6f, 0x75,
0x73, 0x00, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4d, 0x0b, 0x00,
0x08, 0x00, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x43, 0x61,
0x70, 0x72, 0x61, 0x20, 0x66, 0x61, 0x6c, 0x63, 0x6f, 0x6e, 0x65, 0x72,
0x69, 0x00, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4d, 0x01, 0x00,
0x09, 0x00, 0x41, 0x6e, 0x6a, 0x6f, 0x6c, 0x69, 0x65, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x41, 0x69,
0x6c, 0x75, 0x72, 0x75, 0x73, 0x20, 0x66, 0x75, 0x6c, 0x67, 0x65, 0x6e,
0x73, 0x00, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4c, 0x0a, 0x00,
0x0a, 0x00, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x4d, 0x6f,
0x73, 0x63, 0x68, 0x75, 0x73, 0x20, 0x66, 0x75, 0x73, 0x63, 0x75, 0x73,
0x00, 0x00, 0x61, 0x74, 0x75, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x53, 0x05, 0x00,
0x0b, 0x00, 0x41, 0x76, 0x61, 0x00, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x43, 0x65,
0x70, 0x68, 0x61, 0x6c, 0x6f, 0x70, 0x68, 0x75, 0x73, 0x20, 0x6a, 0x65,
0x6e, 0x74, 0x69, 0x6e, 0x6b, 0x69, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4d, 0x0d, 0x00,
0x0c, 0x00, 0x41, 0x78, 0x65, 0x6c, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x48, 0x69,
0x70, 0x70, 0x6f, 0x63, 0x61, 0x6d, 0x65, 0x6c, 0x75, 0x73, 0x20, 0x61,
0x6e, 0x74, 0x69, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x4d, 0x0b, 0x00,
0x0d, 0x00, 0x41, 0x79, 0x61, 0x6e, 0x6e, 0x61, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x47, 0x61,
0x7a, 0x65, 0x6c, 0x6c, 0x61, 0x20, 0x63, 0x75, 0x76, 0x69, 0x65, 0x72,
0x69, 0x00, 0x69, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x53, 0x0c, 0x00,
0x0e, 0x00, 0x42, 0x72, 0x61, 0x64, 0x6c, 0x65, 0x79, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x42, 0x75,
0x62, 0x61, 0x6c, 0x75, 0x73, 0x20, 0x6d, 0x69, 0x6e, 0x64, 0x6f, 0x72,
0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x58, 0x04, 0x00,
0x0f, 0x00, 0x42, 0x72, 0x65, 0x6e, 0x64, 0x61, 0x6e, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x74, 0x01, 0x42, 0x6f,
0x73, 0x20, 0x67, 0x61, 0x75, 0x72, 0x75, 0x73, 0x00, 0x64, 0x6f, 0x72,
0x65, 0x6e, 0x73, 0x69, 0x73, 0x00, 0x73, 0x69, 0x73, 0x00, 0x00, 0x00,
0x5c, 0x3f, 0x1b, 0x00, 0x5c, 0x4f, 0x1b, 0x00, 0x5c, 0x58, 0x01, 0x00
};
unsigned int animals_dat_len = 900;
Code to read binary animals.dat
As I noted in a comment below, the data file leaks information because after each name there is junk data from the previous record. This is one of those occasions where the null-padding behaviour of strncpy()
actually becomes useful; it zaps the extraneous data from previous records with null bytes, but this was signally not done when animals.dat
was generated.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
struct animal {
short int id;
char name[20];
char species[35];
char size;
short int age;
};
static void debris_field(const char *tag, const char *field, size_t length)
{
size_t nomlen = strlen(field);
int count = 0;
for (size_t i = nomlen; i < length; i++)
{
if (field[i] != '\0')
{
if (count == 0)
printf("%8s (%2zu = %-20s) has debris:\n ", tag, nomlen, field);
count++;
unsigned char u = field[i];
if (isprint(u))
putchar(u);
else
printf("\\x%.2X", u);
}
}
if (count != 0)
putchar('\n');
}
static void report_debris(const struct animal *info)
{
debris_field("name", info->name, sizeof(info->name));
debris_field("species", info->species, sizeof(info->species));
}
static void choice2(FILE *infile, int noisy)
{
struct animal info;
while (fread(&info, sizeof(info), 1, infile) == 1)
{
if (strcmp(info.name, "unknown") == 0)
{
printf("Deleted: %2d %20s %30s %c %2d\n", info.id, info.name, info.species, info.size, info.age);
}
else
{
printf("Current: %2d %20s %30s %c %2d\n", info.id, info.name, info.species, info.size, info.age);
}
if (noisy)
report_debris(&info);
}
}
int main(int argc, char **argv)
{
int noisy = 0;
if (argc > 1 && argv[argc] == 0) // Use argv
noisy = 1;
choice2(stdin, noisy);
return 0;
}
The 'use argv
' comment is relevant because I compile with GCC 7.2.0 on a MacBook Pro running macOS High Sierra 10.13.1 with the command line (source in animals59.c
):
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
> -Wstrict-prototypes animals59.c -o animals59
$
If the code didn't use argv
somehow, the compiler would complain and the code wouldn't compile.
Output - no arguments
Current: 1 Abigail Capricornis sumatraensis S 8
Deleted: 2 unknown Oryx leucoryx M 12
Current: 3 Adrian Cephalophus dorsalis L 16
Current: 4 Ahmed Naemorhedus griseus L 10
Current: 5 Aidan Naemorhedus caudatus X 9
Current: 6 Allegra Pseudois nayaur S 5
Current: 7 Amela Cerdocyon thous M 11
Deleted: 8 unknown Capra falconeri M 1
Current: 9 Anjolie Ailurus fulgens L 10
Current: 10 Athena Moschus fuscus S 5
Current: 11 Ava Cephalophus jentinki M 13
Current: 12 Axel Hippocamelus antisensis M 11
Current: 13 Ayanna Gazella cuvieri S 12
Current: 14 Bradley Bubalus mindorensis X 4
Current: 15 Brendan Bos gaurus X 1
Output — with argument
Current: 1 Abigail Capricornis sumatraensis S 8
name ( 7 = Abigail ) has debris:
\x04t\x01t\x01
species (24 = Capricornis sumatraensis) has debris:
\?\x1B\O\x1B\
Deleted: 2 unknown Oryx leucoryx M 12
name ( 7 = unknown ) has debris:
\x04t\x01t\x01
species (13 = Oryx leucoryx ) has debris:
matraensis\?\x1B\O\x1B\
Current: 3 Adrian Cephalophus dorsalis L 16
name ( 6 = Adrian ) has debris:
\x04t\x01t\x01
species (20 = Cephalophus dorsalis) has debris:
sis\?\x1B\O\x1B\
Current: 4 Ahmed Naemorhedus griseus L 10
name ( 5 = Ahmed ) has debris:
\x04t\x01t\x01
species (19 = Naemorhedus griseus ) has debris:
sis\?\x1B\O\x1B\
Current: 5 Aidan Naemorhedus caudatus X 9
name ( 5 = Aidan ) has debris:
\x04t\x01t\x01
species (20 = Naemorhedus caudatus) has debris:
sis\?\x1B\O\x1B\
Current: 6 Allegra Pseudois nayaur S 5
name ( 7 = Allegra ) has debris:
\x04t\x01t\x01
species (15 = Pseudois nayaur ) has debris:
atussis\?\x1B\O\x1B\
Current: 7 Amela Cerdocyon thous M 11
name ( 5 = Amela ) has debris:
a\x04t\x01t\x01
species (15 = Cerdocyon thous ) has debris:
atussis\?\x1B\O\x1B\
Deleted: 8 unknown Capra falconeri M 1
name ( 7 = unknown ) has debris:
\x04t\x01t\x01
species (15 = Capra falconeri ) has debris:
atussis\?\x1B\O\x1B\
Current: 9 Anjolie Ailurus fulgens L 10
name ( 7 = Anjolie ) has debris:
\x04t\x01t\x01
species (15 = Ailurus fulgens ) has debris:
atussis\?\x1B\O\x1B\
Current: 10 Athena Moschus fuscus S 5
name ( 6 = Athena ) has debris:
\x04t\x01t\x01
species (14 = Moschus fuscus ) has debris:
atussis\?\x1B\O\x1B\
Current: 11 Ava Cephalophus jentinki M 13
name ( 3 = Ava ) has debris:
na\x04t\x01t\x01
species (20 = Cephalophus jentinki) has debris:
sis\?\x1B\O\x1B\
Current: 12 Axel Hippocamelus antisensis M 11
name ( 4 = Axel ) has debris:
a\x04t\x01t\x01
species (23 = Hippocamelus antisensis) has debris:
\?\x1B\O\x1B\
Current: 13 Ayanna Gazella cuvieri S 12
name ( 6 = Ayanna ) has debris:
\x04t\x01t\x01
species (15 = Gazella cuvieri ) has debris:
isensis\?\x1B\O\x1B\
Current: 14 Bradley Bubalus mindorensis X 4
name ( 7 = Bradley ) has debris:
\x04t\x01t\x01
species (19 = Bubalus mindorensis ) has debris:
sis\?\x1B\O\x1B\
Current: 15 Brendan Bos gaurus X 1
name ( 7 = Brendan ) has debris:
\x04t\x01t\x01
species (10 = Bos gaurus ) has debris:
dorensissis\?\x1B\O\x1B\