Reading file contents section by section - c

I am trying to read a file contents in sections into useable structs, the '#' symbol begins a section while the '.' symbol ends it. An example would be:
# Type name
bird
mammal
.
# Type effectiveness
VeryEffective
NotEffective
.
So far I can read the contents of the first type, but when I try to read the contents of the second, I keep re-reading the contents of the first.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
typedef struct
{
char types[1000];
char effectiveness[1000];
} sinFile;
sinFile record[1000];
FILE* file;
char line[121];
char period[10];
char Type2[20];
char* item;
char* item2;
int i = 0;
int j;
file = fopen("Test3.txt", "r");
while(fgets(line, 120, file)) {
item = strtok(line, " ");
strcpy(period, ".");
strcpy(Type2, "# Type effectiveness");
if (item[0] == '#' || item[0] == '.') {
continue;
} else {
do {
strcpy(record[i].types, line);
i++;
} while (strcmp(record[i].types, period) == 0);
}
for(j=0; strcmp(line, Type2) == 0; j++) {
do {
strcpy(record[j].effectiveness, line);
j++;
} while (strcmp(record[j].effectiveness, period)== 0);
}
}
fclose(file);
printf("%s", record[1].effectiveness);
}
Currently, record[1].types gives me the same result as record[1].effectiveness; i.e. 'mammal'. I feel like I am close but I'm not sure how to proceed.

There are many issues in this code. To get it worked something like this sample should be used.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
typedef struct
{
char types[1000];
char effectiveness[1000];
} sinFile;
sinFile record[1000];
FILE* file;
char line[121];
char* bp;
int i=0, j=0;
int state=0;
file = fopen("Test3.txt", "r");
while(fgets(line, 120, file)) {
for(bp=line;isspace(*bp);bp++);
if(state==0) {
if(*bp=='#') {
for(bp=line;isspace(*bp);bp++);
item = bp;
if(!strcmp(item,"Type name")) state=1;
else if(!strcmp(item,"Type effectiveness")) state=2;
}
}
else {
if(*bp=='.') {
state=0;
}
else if(state==1) {
strcpy(record[i].types, bp);
i++;
}
else if(state==2) {
strcpy(record[j].effectiveness, bp);
j++;
}
}
}
fclose(file);
printf("%s", record[1].effectiveness);
}
But with this code, the lines in the 1st block have to correspond with the lines in the 2nd block... It would be simpler to use key/value-pairs without blocks.

Related

C: Newbie attemping file reading and struct allocation using malloc

I am trying to store the values stored in a details.txt file into their appropriate place in a dynamically allocated struct. Am I doing something (that should be simple) incorrectly for this not to work? Is it necessary for me to use strtok and split by ','?
My details.txt reads:
mitch,8,1.78,burgers
murray,42,6.5,lasagna
travis,64,1.85,sushi
sam,12,1.94,bacon
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFERSIZE 256
typedef struct
{
char name[BUFFERSIZE];
int favnumber;
float height;
char favfood[BUFFERSIZE];
} Person;
void print_person(Person *p)
{
printf("name: %s\n", p->name);
printf("num: %d\nheight: %.2f\nfav. food: %s\n\n",
p->favnumber, p->height, p->favfood);
}
int count_lines(FILE *fp)
{
int nlines = 0;
char c;
for (c = fgetc(fp); c != EOF; c = fgetc(fp))
{
if (c == '\n')
{
nlines++;
}
}
rewind(fp);
return nlines;
}
int main(void)
{
FILE *fp = fopen("details.txt", "r");
// count lines
int nlines = count_lines(fp);
printf("found %d lines\n\n",nlines);
Person *people = (Person*)malloc(nlines*sizeof(Person));
char buffer[BUFFERSIZE];
int i = 0;
while (fgets(buffer,BUFFERSIZE,fp) != NULL)
{
sscanf(buffer,"%s%d%f%s",people[i].name,
&(people[i].favnumber),
&(people[i].height),people[i].favfood);
print_person(&(people[i]));
i++;
}
printf("found %d people\n",i);
free(people);
fclose(fp);
}
Unfortunately, the current output of my program is:
found 4 lines
name: mitch,8,1.78,burgers
num: 0
height: 0.00
fav. food:
...
found 4 people
The problem is that the first %s parse the the whole line, and you need , in the format string to separate the fields. Not an issue here yet but I also used %[^,] for the last format string so it will not stop at the first space. Also added precision on the strings to avoid buffer overflows:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUFFERSIZE 255
#define str(s) str2(s)
#define str2(s) #s
typedef struct
{
char name[BUFFERSIZE+1];
int favnumber;
float height;
char favfood[BUFFERSIZE+1];
} Person;
void print_person(Person *p)
{
printf("name: %s\n", p->name);
printf("num: %d\nheight: %.2f\nfav. food: %s\n\n",
p->favnumber, p->height, p->favfood);
}
int count_lines(FILE *fp)
{
int nlines = 0;
char c;
for (c = fgetc(fp); c != EOF; c = fgetc(fp))
{
if (c == '\n') {
nlines++;
}
}
rewind(fp);
return nlines;
}
int main(void)
{
FILE *fp = fopen("details.txt", "r");
// count lines
int nlines = count_lines(fp);
printf("found %d lines\n\n",nlines);
Person *people = (Person*)malloc(nlines*sizeof(Person));
char buffer[BUFFERSIZE+1];
int i = 0;
while (fgets(buffer,BUFFERSIZE+1,fp) != NULL)
{
// Changed line, see formatting of %s
sscanf(buffer,
"%" str(BUFFERSIZE) "[^,],%d,%f,%" str(BUFFERSSIZE) "[^,]",
people[i].name,
&(people[i].favnumber),
&(people[i].height),people[i].favfood);
print_person(&(people[i]));
i++;
}
printf("found %d people\n",i);
free(people);
fclose(fp);
}

Handling file reading in c

I'm having a problem with this program. I'm trying to send the pointer to the beginning of a file. It usually works but, when I send the file from one function to another, then fgets gets and empty string rather than the first row in the file.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int checkf(FILE *file, char*id){
char row[255];
int line_num = 1;
int find_result = 0;
char temp[255];
while (fgets(temp, 255, file) != NULL){ // here i get an Empty 'temp'
// so the contition is always false
if((strstr(temp, id)) != NULL) {
rewind(file);
for (int i=1; i<(line_num-1); i++) {
fgets(row, 255, file);
}
for (int i=0; i<4; i++) {
fgets(row, 255, file);
choppy(row);
printf("%s",row);
if (i!=3) {
printf(" ");
}
}
find_result++;
}
line_num++;
}
return find_result;
}
void add(FILE *file, char fileName[20]){
int check;
char name[100], id[100] ;
scanf("%s",name);
scanf("%s",id);
check = checkf(file,id);
if(check==0){
fputs("\n",file);
fputs(name,file);
}
}
int main(int argc, char * argv[]) {
// insert code here...
FILE *file;
FILE *file_app;
file_app= fopen(argv[argc-1], "a");
file= fopen(argv[argc-1],"r");
//check the there is a file
if (file== NULL)
{
printf("Can't open file");
return 1;
}
else
{
int cmd= strcmp(argv[1],"add");
if (cmd==0) add(file_app,argv[2]);
fclose(file);
printf("\n");
return 0;
}
}
So in conclusion, I think that when I the function checkf() is called from function add(), the file pointer gets lost. But, when I use checks() directly it works. Any ideas?

C Turning lines of an archive into arrays

I have an archive and I want to turn every line into an array: v[i].data.
However, when I run the code it shows zeros for the arrays.
Is there anything I should change?
Input
1760
02/20/18,11403.7
02/19/18,11225.3
02/18/18,10551.8
02/17/18,11112.7
02/16/18,10233.9
Actual Output
1761
0
Expected Output
1761
02/20/18,11403.7
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
typedef struct{
char data[20];
}vetor;
int main(int argc,char *argv[]){
FILE *csv;
if((csv=fopen(argv[1], "r")) == NULL )
{
printf("not found csv\n");
exit(1);
}
long int a=0;
char linha[256];
char *token = NULL;
if(fgets(linha, sizeof(linha), csv)) //counting lines
{
token = strtok(linha, "\n");
a =(1 + atoi(token));
}
printf("%d\n", a);
rewind(csv);
vetor *v;
v=(vetor*)malloc(a*sizeof(vetor));
char linha2[256];
while (fgets(linha2, sizeof(linha2), csv) != 0)
{
fseek(csv, +1, SEEK_CUR);
for(int i=0;i<a;i++)
{
fscanf(csv, "%[^\n]", v[i].data);
}
}
printf("%s\n", v[0].data);
fclose(csv);
return 0;
}
There were a number of mistakes so I went ahead and rewrote the problem areas with comments explaining what I did
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char data[20];
}vetor;
int main(int argc,char *argv[]){
FILE *csv;
if((csv=fopen(argv[1], "r")) == NULL )
{
printf("not found csv\n");
exit(1);
}
char line[20];
// Read number of lines
int num_lines = 0;
if (!fgets(line, sizeof(line), csv)) {
printf("Cannot read line\n");
exit(1);
}
char* token = strtok(line, "\n");
num_lines = atoi(token) + 1;
vetor* v = malloc(num_lines * sizeof(vetor));
// Fill in vetor
int i = 0;
while (fgets(line, sizeof(line), csv) != NULL) {
int len = strlen(line);
line[len-1] = '\0'; // replace newline with string terminator
strcpy(v[i].data, line); //copy line into v[i].data
i++;
}
printf("%d\n", num_lines);
for (i = 0; i < num_lines; i++) {
printf("%s\n", v[i].data);
}
return 0;
}
I think the main mistake was a misunderstanding of how best to read in each line of information. If I understood correctly you want each 02/20/18,11403.7 line to be an element in the vetor array.
The easiest way is to simply get each line one at a time with fgets
while (fgets(line, sizeof(line), csv) != NULL)
Change the ending character from newline to the string terminating character '\0'
int len = strlen(line);
line[len-1] = '\0';
Then copy the string into the ith element of vetor and update i for the next iteration of the loop.
strcpy(v[i].data, line);
i++;

Read from a text file and use each line to compare if they are anagrams

I must modify my program to accept input from
a file called anagrams.txt.This file should have two strings per line, separated by the # character. My program should read
each pair of strings and report back if each pair of strings is an anagram. For example consider the following content of anagrams.txt:
hello#elloh
man#nam
Astro#Oastrrasd
Your program should print out the following:
hello#elloh - Anagrams!
man#nam - Anagrams!
Astro#Oastrrasd- Not anagrams!
I should compile in g++
Here is the code to read from text:
int main()
{
char input[30];
if(access( "anagrams.txt", F_OK ) != -1) {
FILE *ptr_file;
char buf[1000];
ptr_file =fopen("anagrams.txt","r"); if (!ptr_file)
return 1;
while (fgets(buf,1000, ptr_file)!=NULL)
printf("%s",buf);
fclose(ptr_file);
printf("\n");
}
else{ //if file does not exist
printf("\nFile not found!\n");
}
return 0;
}
Code to find if the text are anagrams:
#include <stdio.h>
int find_anagram(char [], char []);
int main()
{
char array1[100], array2[100];
int flag;
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
flag = find_anagram(array1, array2);
if (flag == 1)
printf(" %s and %s are anagrams.\n", array1, array2);
else
printf("%s and %s are not anagrams.\n", array1, array2);
return 0;
}
int find_anagram(char array1[], char array2[])
{
int num1[26] = {0}, num2[26] = {0}, i = 0;
while (array1[i] != '\0')
{
num1[array1[i] - 'a']++;
i++;
}
i = 0;
while (array2[i] != '\0')
{
num2[array2[i] -'a']++;
i++;
}
for (i = 0; i < 26; i++)
{
if (num1[i] != num2[i])
return 0;
}
return 1;
}
You can try something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAXLINE 1000
#define MAXLETTER 256
int is_anagram(char *word1, char *word2);
void check_lines(FILE *filename);
int cmpfunc(const void *a, const void *b);
void convert_to_lowercase(char *word);
int
main(int argc, char const *argv[]) {
FILE *filename;
if ((filename = fopen("anagram.txt", "r")) == NULL) {
fprintf(stderr, "Error opening file\n");
exit(EXIT_FAILURE);
}
check_lines(filename);
fclose(filename);
return 0;
}
void
check_lines(FILE *filename) {
char line[MAXLINE];
char *word1, *word2, *copy1, *copy2;
while (fgets(line, MAXLINE, filename) != NULL) {
word1 = strtok(line, "#");
word2 = strtok(NULL, "\n");
copy1 = strdup(word1);
copy2 = strdup(word2);
convert_to_lowercase(copy1);
convert_to_lowercase(copy2);
if (is_anagram(copy1, copy2)) {
printf("%s#%s - Anagrams!\n", word1, word2);
} else {
printf("%s#%s - Not Anagrams!\n", word1, word2);
}
}
}
void
convert_to_lowercase(char *word) {
int i;
for (i = 0; word[i] != '\0'; i++) {
word[i] = tolower(word[i]);
}
}
int
is_anagram(char *word1, char *word2) {
qsort(word1, strlen(word1), sizeof(*word1), cmpfunc);
qsort(word2, strlen(word2), sizeof(*word2), cmpfunc);
if (strcmp(word1, word2) == 0) {
return 1;
}
return 0;
}
int
cmpfunc(const void *a, const void *b) {
if ((*(char*)a) < (*(char*)b)) {
return -1;
}
if ((*(char*)a) > (*(char*)b)) {
return +1;
}
return 0;
}
Since this looks like a University question, I won't provide a full solution, only a hint.
All you have to do is replace the stdin input part of the anagram-finding file with the code you wrote to read from a file: it's as simple as changing
printf("Enter the string\n");
gets(array1);
printf("Enter another string\n");
gets(array2);
to
// before program:
#define SIZE 1000
// inside main
if (access("anagrams.txt", F_OK) == -1){
printf("\nFile not found!\n");
return 1; // Abort the program early if we can't find the file
}
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("anagrams.txt","r");
if (!ptr_file)
return 1;
char array1[SIZE], array2[SIZE];
while (fgets(buf, 1000, ptr_file)!=NULL){
// do all your anagram stuff here!
// there is currently one line of the input file stored in buf
// Hint: You need to split buf into array_1 and array_2 using '#' to separate it.
}
fclose(ptr_file);
printf("\n");
Additional comments:
Don't ever ever ever use gets. gets doesn't check that the string it writes to can hold the data, which will cause your program to crash if it gets input bigger than the array size. Use fgets(buf, BUF_SIZE, stdin) instead.
Beautiful code is good code. People are more likely to help if they can read your code easily. (fix your brackets)
Just for interest, a more efficient algorithm for checking anagrams is to use qsort to sort both arrays, then a simple string matcher to compare them. This will have cost O(mnlog(m+n)), as opposed to O(m^2 n^2), awith the current algorithm
You need to split every line you read by fgets (as you did) in to two strings, and pass them to your find_anagram function. You can do that using strtok:
int main()
{
int flag;
char buf[1000];
FILE *ptr_file;
//Check file existence
//Open the file for reading
while (fgets (buf, 1000, ptr_file) != NULL)
{
char *array1 = strtok(buf, "#");
char *array2 = strtok(NULL, "\n");
flag = find_anagram (array1, array2);
//Check flag value to print your message
}
return 0;
}
//put your find_anagram function
Don't forget to #include <string.h> to use strtok().

passing struct in function

I spend lot of time to pass a struct pointer in a function. everything in the code is working only I couldn't figure out how to pass a struct in a function then I can do some operation inside a function. can you explain where exactly i'm fail and how to fix it? Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i=0;
int* i_ptr=&i;
int count(int q);
int line_count();
struct student {
int st_id;
char st_name[20];
int st_age;
char st_dep[7];
float st_grade;
};
int sort_student(struct student line[i],int i)
{
printf("%f",line[1].st_grade);
printf(" %s",line[1].st_name);
return 0;
}
int main()
{
/* struct loading from the file operation goes here */
int x=0;
int i=line_count();
struct student line[i];
char file_line[100];
char* line_parts;
FILE * fp;
if ((fp = fopen (file.txt", "r")) != NULL)
{
while (x<i) {
if(fgets(file_line,100,fp) != NULL); // gets line from the file.
{
line_parts = strtok(file_line,","); // breaks the line
line[x].st_id = atoi(line_parts); // conversition string to int
line_parts = strtok(NULL, ",");
strcpy(line[x].st_name,line_parts);
line_parts = strtok(NULL, ",");
line[x].st_age = atoi(line_parts);
line_parts = strtok(NULL, ",");
strcpy(line[x].st_dep,line_parts);
line_parts = strtok(NULL, ",");
line[x].st_grade = atoi(line_parts);
x++;
}
}
}
fclose(fp);
sort_student(&line[i],i);
return 0;
}
int line_count () //counts the number of line in the file, while loading the program.
{
FILE * fp; // file open from here.
int i=0;
int c;
if ((fp = fopen ("/Users/rishav/Desktop/try/try/file.txt", "r")) != NULL)
{
while ((c=fgetc(fp)) != EOF) {
if (c=='\n') {
i++;
}
}
fclose(fp);
}
else printf("file reading Error.\n");
return i;
}
int count(q) // keeps track of i
{
if(q==1)
{
(*i_ptr)++;
}
return *i_ptr;
}
You need to change your sort_student function definition to
int sort_student(struct student* line,int i) {
printf("%f",line->st_grade);
printf(" %s",line->st_name);
return 0;
}

Resources