load information from file to table - c

I want to load information from the file to store in a table but I find that there's an error during loading the information and that the function void charger_Etudiant(Etudiant *E) does not display the information as they are stored in the file, someone to help me please :)
typedef struct Etudiant
{
char nom[64];
char prenom[64];
char CNI[64];
int sante;
int niveau_scolaire;
int Code_confidentiel;
int CNE;
} Etudiant;
the function is:
void charger_Etudiant(Etudiant *E)
{
int i=0;
FILE *fichier = NULL;
fichier = fopen("Info_Etudiant.txt", "r");
if (fichier != NULL)
{
while(i<2&&!feof(fichier))
{
fscanf(fichier,"%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",&E[i].Code_confidentiel,E[i].nom,E[i].prenom,&E[i].CNE,E[i].CNI,&E[i].niveau_scolaire,&E[i].sante);
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",E[i].Code_confidentiel,E[i].nom,E[i].prenom,E[i].CNE,E[i].CNI,E[i].niveau_scolaire,E[i].sante);
i++;
}
fclose(fichier);
}
}
for exemple the information in the file is written in the following form and I want to store them in a table structure :
123 BADR HARI 10043720 SJ26825 1 3

I am not a fan of scanf() or of fscanf(). I prefer to use fgets() and strtok() and sscanf() to extract the fields, although here atoi() is good enough. One advantage of strtok() is that if the field delimitors change, there is only one tweak required.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRLENG 63
typedef struct Etudiant {
char nom [STRLENG+1];
char prenom [STRLENG+1];
char CNI [STRLENG+1];
int sante;
int niveau_scolaire;
int Code_confidentiel;
int CNE;
} Etudiant;
int charger_Etudiant(Etudiant *E) {
int i=0;
char buff[512];
char *tok;
char delims[] = "\t\n";
FILE *fichier = NULL;
fichier = fopen("Info_Etudiant.txt", "r");
if (fichier != NULL) {
while(fgets (buff, 512, fichier) != NULL) {
memset(&E[i], 0, sizeof(Etudiant));
if (tok = strtok (buff, delims)) {
E[i].Code_confidentiel = atoi(tok);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].nom, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].prenom, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
E[i].CNE = atoi(tok);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].CNI, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
E[i].niveau_scolaire = atoi(tok);
if (tok = strtok (NULL, delims)) {
E[i].sante = atoi(tok);
}
}
}
}
}
}
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d\n",
E[i].Code_confidentiel, E[i].nom, E[i].prenom,
E[i].CNE, E[i].CNI,E[i].niveau_scolaire,E[i].sante);
i++;
}
}
fclose(fichier);
}
return i;
}
int main() {
return 0;
}

Do not use feof() to detect EOF condition. Check the return value from input functions instead.
Like #Weather Vane suggest using fgets()
.
#define MAXINTLEN (20)
// Use 2x size line buffer
#define MAXLINELEN ((sizeof(Etudiant) + 4*MAXINTLEN) * 2)
char buffer[MAXLINELEN + 2];
while (fgets(buffer, sizeof buffer, fichier) != NULL) {
int cnt = sscanf(buffer,"%d%63s%63s%d%63s%d%d",
&E[i].Code_confidentiel, E[i].nom, E[i].prenom, &E[i].CNE,
E[i].CNI, &E[i].niveau_scolaire, &E[i].sante);
if (cnt != 7) {
break; // scan error
}
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",
E[i].Code_confidentiel, E[i].nom, E[i].prenom, E[i].CNE,
E[i].CNI, E[i].niveau_scolaire, E[i].sante);
i++;
}
When scanning the "\t\t" does not necessarily scan 2 tabs. Any white space in scanf() (except in %[]) scans any number of white spaces. Code could use sscanf(buffer,"%d %63s %63s %d %63s %d %d", ... for clarity, but it does the same thing.
Specifiers "%d" and "%s" consume leading white-space anyways.
Always limit string inputs. Example: %63s

Related

How to read from the file and write it in the structure? I have a little trouble with my code

I have to write this code, I mean I should read from the file name of students and their mark, and then sort students by the grow of mark. Now I just want to output only mark. I want to display grades using structures. I don't know where the problem is.
text.file
Jon 3
Alina 5
Ron 1
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
int main()
{
const int N = 3;
int i = 0;
struct student {
char surname[50];
int mark;
};
struct student PI1[N];
char str[50];
const char s[1] = " ";
char* token;
FILE* ptr;
token = strtok(str, s);
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
while (fgets(str, 50, ptr) != NULL){
token = strtok(str, s);
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
PI1[i].mark = atoi(token);
i++;
}
fclose(ptr);
printf("The marks is:\n");
printf("%d %d %d", PI1[0].mark, PI1[1].mark, PI1[2].mark);
return 0;
}
You need to prevent the program from reading from the file pointer if opening the file fails:
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
perror("test.txt");
return 1; // this could be one way
}
The second argument to strok should be a null terminated string. const char s[1] = " "; only has room for one character. No null terminator (\0). Make it:
const char s[] = " "; // or const char s[2] = " "; or const char *s = " ";
Don't iterate out of bounds. You need to check so that you don't try to put data in PI1[N] etc.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
// ^^^^^^^^
Check that strok actually returns a pointer to a new token. If it doesn't, the line you've read doesn't fulfill the requirements.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
token = strtok(str, s);
if(!token) break; // token check
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
if (token) // token check
PI1[i].mark = atoi(token);
else
break;
i++;
}
You could also skip the strcpy by reading directly into your struct student since char str[50]; has the same length as surname. str should probably be larger though, but for now:
while (i < N && fgets(PI1[i].surname, sizeof PI1[i].surname, ptr) != NULL) {
token = strtok(PI1[i].surname, s);
if(!token) break;
token = strtok(NULL, s);
if (token)
PI1[i].mark = atoi(token);
else
break;
i++;
}
Only print as many marks as you successfully read
printf("The marks are:\n");
for(int idx = 0; idx < i; ++idx) {
printf("%d ", PI1[idx].mark);
}
putchar('\n');

File reading in C with fgets entering into a never ending loop

I'm attempting to do basic file reading in C with fgets. It should read one line, pass it to the tokeniser function which should split it at every ' ' and add it to a linked list. At the moment it is entering into a never ending while loop and I'm not sure why. Any help is appreciated. I am really struggling with this C language
#define INPUTSIZE 11
void tokeniseString(LinkedList *list, char *str)
{
char *token = strtok(str, " ");
while (token != NULL)
{
insertLast(list, *token);
}
}
void readInputFile(char *fileName, LinkedList *list)
{
FILE* inputFile = fopen(fileName, "r");
char str[INPUTSIZE];
printf("1");
if (inputFile == NULL)
{
perror("Could not open file");
}
else
{
while (fgets(str, INPUTSIZE, inputFile) != NULL)
{
tokeniseString(list, str);
}
if (ferror(inputFile))
{
perror("Error while reading from file");
}
}
}
You have an endless loop because you do not scan for the next token in the loop body. You should write:
void tokeniseString(LinkedList *list, char *str) {
char *token = strtok(str, " ");
while (token != NULL) {
insertLast(list, *token);
token = strtok(NULL, " ");
}
}
Not however that you insert the value of the first byte of the token into the list. You should probably convert the token as a number using strtol() instead:
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
void tokeniseString(LinkedList *list, char *str) {
char *token = strtok(str, " \t\r\n");
while (token != NULL) {
char *p;
long value;
errno = 0;
value = strtol(token, &p, 10);
if (p == token || *p != '\0') {
fprintf(stderr, "token is not a number: %s\n", token);
} else
if (errno != 0 || value > INT_MAX || value < INT_MIN) {
fprintf(stderr, "number is out of range: %s\n", token);
} else {
insertLast(list, (int)value);
}
token = strtok(NULL, " \t\r\n");
}
}
Note that modifying the string argument is considered bad practice, especially using a function with side effects on a static state such as strtok(). Here is another version that does not modify the argument:
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void tokeniseString(LinkedList *list, const char *str) {
for (;;) {
char *p;
long value;
int len;
/* skip whitespace */
str += strspn(str, " \t\r\n");
if (*str == '\0')
break;
/* get the length of the token */
len = strcspn(str, " \t\r\n");
errno = 0;
value = strtol(token, &p, 10);
if (p == str) {
fprintf(stderr, "token is not a number: %.*s\n", len, str);
} else
if (p != str + len) {
fprintf(stderr, "token has extra characters: %.*s\n", len, str);
} else
if (errno != 0 || value > INT_MAX || value < INT_MIN) {
fprintf(stderr, "number is out of range: %.*s\n", len, str);
} else {
insertLast(list, (int)value);
}
str += len;
}
}
Also note that you must close the file in readInputFile().

C Programming - can't copy string from buffer to given char array using pointers

I'm not sure where I'm messing up so I've given a summary of each function so my logic can be checked!
The main program takes arguments from the command line and stores them in char pointer array.
The correct command to run program is ./re-do_hw4_prob6 filename. (filename is sears_kmart_stores_closing_2019.txt in this case)
After checking if argument number is correct, the file is opened.
A while loop copies strings of text from file to buffer until NULL is met.
Then the function getState() is called. The state is printed.
The file is closed.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "redo_hw4_functs.h"
int main(int argc, char* argv[])
{
char** states;
FILE* pFile;
char buffer[80];
int i = 0;
if(argc < 2){
printf("Too few arguments! \n");
}
else if(argc > 2){
printf("Too many arguments! \n");
}
pFile = fopen(argv[1], "r");
states = malloc(50*sizeof(char));
for (i = 0; i < 50; i++)
{
states[i] = malloc(3*sizeof(char));
while(fgets(buffer, sizeof(buffer), pFile) != NULL)
{
getState(states[i], buffer);
printf("State: %s \n", states[i]);
}
}
fclose(pFile);
}
The getState() function takes in two char arrays. One to read from the other to copy too.
It tokenizes the string being read from using a comma, a tab, and a new line as the delimiters. -> ",\t\n"
On the last token it copies the last two chars to the empty string array.
//accepts a line of string formatted as expected and stores the store state in char file ¡OJO! This is the hardest one because you cant rely on delimeters alone to find state
void getState(char strState[], char strLine[])
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = (strlen(token) - 2); i < strlen(token); i++)
{
strState[i] =token[i];
}
}
I have also included my other functions to see if there are any other mistakes to be corrected.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "redo_hw4_functs.h"
//accepts a line of string formatted as expected and stores the store name in char file
void getName(char strName[], char strLine[])
{
char* token;
char delim[] = " ,\t\n";
token = strtok(strLine, delim);
while(token != NULL)
{
if(strcmp(token, "sears") == 0 || strcmp(token, "kmart"))
{
strcpy(strName, token);
break;
}
token = strtok(NULL, delim);
}
}
//accepts a line of string formatted as expected and stores the store address in char file
void getAddress(char strAddress[], char strLine[])
{
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
while(token != NULL)
{
if(isdigit(token[0]) && isalpha(token[sizeof(token)-1]))
{
strcpy(strAddress, token);
break;
}
token = strtok(NULL, delim);
}
}
//accepts a line of string formatted as expected and stores the store city in char file
void getCity(char strCity[], char strLine[])
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = 0; i < (strlen(token) - 3); i++)
{
strcpy(strCity[i], token[i]);
}
}
//accepts a line of string formatted as expected and stores the store state in char file ¡OJO! This is the hardest one because you cant rely on delimeters alone to find state
void getState(char strState[], char strLine)
{
int i;
char* token;
char delim[] = ",\t\n";
token = strtok(strLine, delim);
token = strtok(strLine, delim);
token = strtok(strLine, delim);
for(i = (strlen(token) - 2); i < strlen(token); i++)
{
strcpy(strState[i], token[i]);
}
}
Here is an example of input text that is to be read:
Kmart, 217 Forks Of River Pkwy, Sevierville TN
Kmart, 4110 E Sprague Ave, Spokane WA
Kmart, 1450 Summit Avenue, Oconomowoc WI
Sears, 2050 Southgate Rd, Colorado Spgs CO
Sears, 1650 Briargate Blvd, Colorado Spgs CO
Sears, 3201 Dillon Dr, Pueblo CO
Here is an example of what the program is expected to be outputting:
State:TN
State:WA
State:WI
State:CO
State:CO
State:CO
Here is an example of what the program is outputting:
I assume that you want not only the status but also all the other fields so that you can deal with them later.
The code below may be quite different from yours, but I think that it is easier to use a single function to read each record.
The function read_data() reads data from the file pointer fp and store them in data, which is a pointer to a predefined struct data_t.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1024
typedef struct {
char name[64];
char addr[64];
char city[64];
char state[8];
} data_t;
int read_data(FILE *fp, data_t *data) {
char buffer[BUFFER_SIZE];
// Read a record. If end-of-file is read, return -1.
if (fgets(buffer, BUFFER_SIZE, fp) == NULL) {
return -1;
}
char delim[] = ",\t\n";
// Find the name of the record.
char *token = strtok(buffer, delim);
strcpy(data->name, token);
// Find the address of the record.
token = strtok(NULL, delim);
while (*token == ' ') {
++token;
}
strcpy(data->addr, token);
// Find the city and status of the record.
// We cannot split them by strtok() easily, so we handle it later.
token = strtok(NULL, delim);
while (*token == ' ') {
++token;
}
// Find the position of the state.
char *ptr = token;
while (*ptr != '\0') {
++ptr;
}
ptr -= 2;
strcpy(data->state, ptr);
// Use NULL to separate the city and the state so that we can use strcpy().
while (*(ptr - 1) == ' ') {
--ptr;
}
*ptr = '\0';
// Copy the city field.
strcpy(data->city, token);
return 0;
}
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "The number of arguments is incorrect.\n");
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return -1;
}
FILE *fp = fopen(argv[1], "r");
data_t *data = malloc(sizeof(data_t));
while (read_data(fp, data) == 0) {
printf("State: %s\n", data->state);
}
free(data);
fclose(fp);
return 0;
}
The way to read data is hard-coded, so if the input format is different, you may need to change the content of read_data(), but it works well for your sample input.

How to read a CSV file in C

I am trying to read a CSV file of the following format:
5,455,78,5
12245,4,78
1,455,4557,1,8,9
I have managed to open the file but I have no idea how to interpret the data. All the data is written in the first column, but I do not know how many rows there are or how many entries there is in each row.
This is my code for opening the file.
printf("File chosen is: %s",file);
int p=0;
FILE *myFile = NULL;
myFile = fopen(file,"r");
if (myFile == NULL)
{
exit(1);
}
if (myFile != NULL)
{
printf("\n\nFile read succesfully");
}
This should parse your csv. After opening you file, read each line using fgets. Loop through until fgets returns NULL which indicates no line could be read and you reached the end of your file. Use strtok to parse your line from fgets using the comma as your delimiter.
#include <stdio.h> // file handling functions
#include <stdlib.h> // atoi
#include <string.h> // strtok
...
char buffer[80];
while (fgets(buffer, 80, myFile)) {
// If you only need the first column of each row
char *token = strtok(buffer, ",");
if (token) {
int n = atoi(token);
printf("%d\n", n);
}
// If you need all the values in a row
char *token = strtok(buffer, ",");
while (token) {
// Just printing each integer here but handle as needed
int n = atoi(token);
printf("%d\n", n);
token = strtok(NULL, ",");
}
}
...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char* getfield(char* line, int num)
{
const char* tok;
for (tok = strtok(line, ",");
tok && *tok;
tok = strtok(NULL, ",\n"))
{
if (!--num)
return tok;
}
return NULL;
}
int main()
{
FILE *stream = fopen("yourfile.csv", "r");
int i = 0;
int j = 0;
printf("Choose a line to be given its elements: ");
scanf("%d", &j);
char line[1024];
while (fgets(line, 1024, stream))
{
char* tmp = _strdup(line);
i++;
printf("Element %d would be %s\n", i, getfield(tmp, j));
free(tmp);
}
}
Thank you for posting some code, but you don't mention what you wish to do with your data once you read it in.
I'll give you some pointers:
Use an array of known size to read your data into from the file and buffer it for processing. Run this in a loop. e.g.
char buffer[1000];
while (fgets(buffer, sizeof (buffer), myFile))
{
char *data = strtok(buffer, ",");
printf("Data %s\n", data);
/* Further processing of data */
data = strtok(NULL, ",");
}
fclose(myFile);
Process that buffer using strtok to separate out your strings. The token is the data delimiter which should be ',' but I'm not clear on whether you also have a newline character in there, but it needs to be consistent.
Handle your strings returned above.

C - Read from .INI file and pass values to vars

I'm doing a project for school and I need to read from an .INI file to start my vars for the game. Problem is, I cannot seem to understand how strtok works and I'm really confused at this point.
I know I'm returning an empty struct because I have no idea how to put the specific values into the vars!
Here's my read_from_config.h
#ifndef READ_FROM_CONFIG_H
#define READ_FROM_CONFIG_H
#define MAXSTR 500
typedef struct {
unsigned int xdim;
unsigned int ydim;
unsigned int nzombies;
unsigned int nhumans;
unsigned int nzplayers;
unsigned int nhplayers;
unsigned int turns;
} CONFIG;
CONFIG read_config(char *argv[]);
#endif
And here is my read_from_config.c
#include "read_from_config.h"
#include "example.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
CONFIG read_config(char *argv[]) {
char str[MAXSTR];
FILE *fp = NULL;
char *filename = argv[1];
char *token;
fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Não foi possível abrir ficheiro de configuração.");
fprintf(stderr, "\nModo de uso: ./program_name config.ini");
}
while (fgets(str, MAXSTR, fp) != NULL) {
for (int i = 0; i != '\0'; i++) {
char *equal = strpbrk (str, "=");
if (equal) {
token = strtok(str, "=");
}
}
}
printf("%d", token[0]);
CONFIG config;
return config;
}
CONFIG.INI
; Dimension of the grid
xdim=20
ydim=20
; Inicial number of zombies and humans
nzombies=20
nhumans=20
; Number of zombies and humans controlled by players
nzplayers=0
nhplayers=1
; Number of maximum turns
maxturns=1000
The function strtok take a string only the first time it gets called. All
subsequent calls must be passed with NULL
man strtok
#include <string.h>
char *strtok(char *str, const char *delim);
DESCRIPTION
The strtok() function breaks a string into a sequence of zero or more nonempty tokens.
On the first call to strtok(), the string to be parsed should be specified in str.
In each subsequent call that should parse the same string, str must be NULL.
Example:
char line[] = "a,b,c,d,e,f\n"; // to simulate an fgets line
char *token = strtok(line, ",\n"); // you can add \n to the separator
// to get rid of the \n at the end
puts(token); // prints a
while(token = strtok(NULL, ",\n"))
puts(token); // prints b then c etc..
Keep in mind that strtok modifies the source, this is going to fail:
strtok("a,b,c", ",");
because string literals are not modifiable. In that case you have to make a copy
to a char[] or a dynamic allocated char*.
If you need to have the source intact after the parsing, then you definitively
need to make a copy.
In your code you do:
printf("%d", token[0]);
That's not incorrect but perhaps not what you want to do. This line doesn't
print the first character, it prints the ascii value of the first character.
This
printf("%c", token[0]);
will print the first character.
Also you are doing
CONFIG read_config(char *argv[]) {
...
CONFIG config;
return config;
}
You are returning an uninitialized CONFIG object, you are ignoring the parsing
and nothing is set in your config object.
Your parsing is also a little bit strange.
for (int i = 0; i != '\0'; i++)
The loop exits immediately because 0 == '\0'! I don't understand what you are
trying to do with it.
I would first create a helper function to populate the values of the config, see
set_config_val. Then you can parse it like this:
CONFIG read_config(char *argv[]) {
...
const char *delim = "=\n";
CONFIG config;
while (fgets(str, MAXSTR, fp) != NULL) {
if(strchr(str, '='))
{
char varname[100];
int value;
token = strtok(line, delim);
strcpy(varname, token);
token = strtok(NULL, delim);
value = atoi(token);
set_config_val(&config, varname, value);
} else {
fprintf(stderr, "Skipping line, no = found");
}
}
fclose(fp);
return config;
}
void set_config_val(CONFIG *config, const char *key, int val)
{
if(config == NULL)
return;
if(strcmp(key, "xdim") == 0)
config->xdim = val;
else if(strcmp(key, "ydim") == 0)
config->ydim = val;
...
}

Resources