Scanning multiple line data from .txt file into struct array - c

I have a text file where info looks like this:
he he 5 5 5 5 5 5 5 5 5 5 5
ne ne 5 5 5 5 5 5 5 5 5 5 5
and I can keep adding to it.
What I want to do is have a function that reads that info and puts in into struct array, but I'm having trouble with pointers and figuring out how to read one line, then next one etc. I'm aware function that reads atm is broken, I tried bunch of stuff and could not figure it out. Sorry if its a bit silly question.
Source.c
int main(void) {
int opcija=0;
U *ucenici=NULL;
while(opcija !=4){
printf("Odaberite opciju:\n 1.Stvaranje datoteke ucenici.txt\n 2.Upisivanje novog ucenika\n 3.Pregled ucenika\n 4.Izlaz iz programa\n");
scanf("%d", &opcija);
switch (opcija) {
case 1:
kreiranje();
break;
case 2:
dodavanje();
break;
case 3:
void citanje1(U *ucenici);
int j=brojanjelinija();
for (int i = 0;i < j; i++) {
printf("%d. %s %s\n", i + 1, ucenici[i].ime, ucenici[i].prezime);
}
}
}
return 0;
}
void citanje1(U **ucen) {
FILE* pok = NULL;
pok = fopen("ucenici.txt", "r");
int broj = brojanjelinija();
ucen = (U**)malloc(broj * sizeof(U*));
for (int i = 0;i < broj;i++) {
fscanf(pok, "%s %s %d %d %d %d %d %d %d %d %d %d %d \n", ucen[i]->ime, ucen[i]->prezime, ucen[i]->dan, ucen[i]->mjesec, ucen[i]->godina, ucen[i]->mat, ucen[i]->hrv, ucen[i]->eng, ucen[i]->hidr, ucen[i]->fiz, ucen[i]->term, ucen[i]->oet, ucen[i]->tehmat);
}
free(ucen);
}
Header.h
#ifndef HEADER_H
#define HEADER_H
typedef struct ucenik{
char ime[10];
char prezime[10];
int* dan;
int* mjesec;
int* godina;
int* mat;
int* hrv;
int* eng;
int* hidr;
int* fiz;
int* term;
int* oet;
int* tehmat;
}U;
void kreiranje(void);
void dodavanje();
int brojanjelinija();
void citanje1(U);
#endif // HEADER_H

All your ucinek data members that you want to use to store integers should actually store int instead of int*:
int dan;
int mjesec;
...etc...
Remember that a pointer tells the compiler where to find some other data, rather than storing a meaningful value itself.
Your fscanf line should then change to pass pointers to the integers, which you can get using the & operator:
fscanf(pok, "%s %s %d %d %d %d %d %d %d %d %d %d %d\n",
ucen[i]->ime, ucen[i]->prezime, &ucen[i]->dan, &ucen[i]->mjesec,
&ucen[i]->godina, &ucen[i]->mat, &ucen[i]->hrv, &ucen[i]->eng,
&ucen[i]->hidr, &ucen[i]->fiz, &ucen[i]->term, &ucen[i]->oet,
&ucen[i]->tehmat);
Those pointers tell fscanf where to store the parsed values.
I never use fscanf without checking the returned value either: it says how many values were successfully parsed from the input and stored. If it's not the number you're expecting, you should print an error message.

Related

How to load text file in typedef struct?

I am having a problem to save all elements in when ı print it prints first line, or it prints with errors and bugs, ı want to start from second line.
Text in file:
5 5 7
H 1 1 MILK White liquid produced by the mammals
H 2 1 IN Used to indicate inclusion within space, a place, or limits
H 3 3 BUS A road vehicle designed to carry many passengers
H 5 3 DAN The name of a famous author whose surname is Brown
V 1 1 MIND A set of cognitive faculties, e.g. consciousness, perception, etc.
V 3 3 BAD Opposite of good
V 2 5 ISBN International Standard Book Number
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
char *word; //word and corresponding hint
char *clue;
int x; //Starting x and y positions
int y;
char direction; //H for horizontal, V for vertical
int f; //solved or not
} Word_t;
int main()
{
int nrWords=7;
FILE * fpointer = fopen("puzzle2010.txt","r");
loadTextFile(fpointer,nrWords);
return 0;
}
Word_t* loadTextFile( FILE* fpointer, int nrWords ){
Word_t* tfile;
int deta,dete,data;
int i=0;
char skip[100];
tfile = (Word_t*) malloc(sizeof(Word_t)*nrWords);
for(i=0;i<nrWords;i++){
if(i==0){
fscanf(fpointer,"%d %d %d ",&data,&dete,&deta);
printf("%d %d %d \n",data,dete,deta);
}
else{
fscanf(fpointer,"%c %d %d %s %s ",&tfile[i].direction,&tfile[i].x,&tfile[i].y,tfile[i].word,&tfile[i].clue);
printf("%c %d %d %s %s ",tfile[i].direction,tfile[i].x,tfile[i].y,tfile[i].word,tfile[i].clue);
}
}
fclose(fpointer);
}

Storing values from file to struct array in C

I am trying to read values from my text file and store them in struct array. My text file has these values:
names.txt
Num_of_rec: 5
3 7 10 1 red
5 6 8 2 red
9 9 16 5 blue
13 4 19 2 green
12 8 15 4 blue
And my code so far is this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ERROR -1
#define MAXLEN 256
struct Point {
float x;
float y;
};
struct Rectangle {
struct Point top_left;
struct Point bottom_right;
char color[7];
};
int main() {
int i, N;
char junk[MAXLEN];
struct Rectangle *data;
FILE *fp;
fp = fopen("names.txt", "r");
fscanf(fp,"%s %d\n",junk,&N);
printf("No: %d", N);
data = (struct Rectangle *) malloc(N*sizeof(struct Rectangle));
for(i=0; i<N; i++) {
fscanf(fp, "%lf %lf %lf %lf %s", data[i].top_left.x, data[i].top_left.y, data[i].bottom_right.x, data[i].bottom_right.y);
}
return 0;
}
I want to add all these values in a struct array(data), but I don't know how to do this properly. Until now the output is:
No: 5
and it just crash. I don't understand if the problem is the method that I am using to read the values from the file and store them to the struct array, or something else.
fscanf(fp, "%lf %lf %lf %lf %s", data[i].top_left.x, data[i].top_left.y, data[i].bottom_right.x, data[i].bottom_right.y);
There are three problems regarding fscanf:
fscanf takes pointers, you pass in values
fscanf expects 5 pointers, you only provide 4 values.
format specifier %lf expects a pointer to a double type
Changing the above statement to the follow should solve the crash.
fscanf(fp, "%f %f %f %f %s", &data[i].top_left.x, &data[i].top_left.y, &data[i].bottom_right.x, &data[i].bottom_right.y, data[i].color);

Printing the data in multiple structs

I'm working with four differest structs, two of which are quite large. I have a function to write each value of each struct to a .txt file, but the code is very long and robust. I'm looking for a way of printing out each value without having to hard code each in, but everything I've found so far in my research indicates that hardcoding is the only way, but I figured I'd check on here before I give up completely. As it stands right now, my code looks like this:
char text[416];
snprintf(text, 416,
"%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
epsy.VBUS_voltage_mV,
epsy.temp_internal_degC,
epsy.status,
batty.Z_pos_Camera_Temperature,
batty.Z_neg_Camera_Temperature,
batty.Y_pos_Camera_Temperature,
batty.Y_neg_Camera_Temperature,
batty.X_pos_Camera_Temperature,
batty.FPGA_Temp_1,
batty.FPGA_Temp_2,
batty.Rx_Hinge_Temperature,
batty.Bat_1_Vbat,
batty.Bat_1_Ichg,
batty.Bat_1_Idch,
batty.Bat_1_MCU_Temp,
batty.Bat_1_Temp_Therm,
batty.Bat_1_Status,
batty.Bat_2_Vbat,
batty.Bat_2_Ichg,
batty.Bat_2_Idch,
batty.Bat_2_MCU_Temp,
... and it goes on for a while. (80 values)
Is there a simpler way of doing this? If so, how do I do it?
The following solution defines a union that combines the actual struct with it's integral members with an array of integral values in order to "view" the struct members as array elements accessible through subscription.
To make this save, we need to control the alignment, since the compiler might add padding between the data members. This would then let the "array-view" point to invalid memory and introduce undefined behaviour.
I suggest to use #pragma pack(n) to control the alignment. Note that the code may also work without this alignment thing, yet it might get a problem if data members of other type are introduced before or after the "integral block" (This would also require to offset the "array-view", but that's not shown here).
The surrounding union is required to guarantee that the array and the struct are actually aligned correctly; otherwise, a cast from a struct to an array might introduce undefined behaviour.
I'm aware that #pragma pack is not portable and that it affects the memory layout and probably speed. Yet it is supposed to work on most compilers, and I think it is needed for controlling alignment in order to avoid UB:
#pragma pack(4) /* set alignment to 4 byte boundary */
#define nrOfMyPackedDataElements 3
union MyPackedData {
struct {
int32_t firstInt;
int32_t secondInt;
int32_t thirdInt;
} data;
int32_t array[nrOfMyPackedDataElements];
};
#pragma pack() /* reset alignment to compiler default */
int main() {
union MyPackedData data;
data.data.firstInt = 10;
data.data.secondInt = 20;
data.data.thirdInt = 30;
for (int i=0; i < nrOfMyPackedDataElements; i++) {
printf("%d ",data.array[i]);
}
return 0;
}
In C11 you could rewrite your structs using unnamed structures and union fields.
Something like this:
#include <stdio.h>
struct dir_t
{
int pos;
int neg;
};
struct cam_temp_t
{
dir_t x;
dir_t y;
dir_t z;
};
// it seems that you have only ints in your structure...
#define TOTAL_N_INTS 8
struct batty_t
{
union
{
int data_[TOTAL_N_INTS];
struct
{
struct cam_temp_t camera_temperature;
int fpga; // you get it...
int bat;
}
};
};
int main(void)
{
struct batty_t example = {
.camera_temperature = {
.x = {3, 4},
.y = {5, 6},
.z = {7, 8}
},
.fpga = 1,
.bat = 2
};
for (int i = 0; i < TOTAL_N_INTS; ++i )
{
printf("%4d", example.data_[i]);
}
return 0;
}
Of course if you have different types, you should use different arrays.
Accessing an int array via a struct and visa-versa like this answer might be valid, might not. Yet I am now not so confident for its use with general types. Leaving this as wiki for anyone to add/amend/delete.
OP later commented that the struct members are not all int. Oh well.
If all members are and forever will be int ...
Access each member, one at a time by int offset.
Some untested code to illustrate the idea:
int print_int_struct(char *dest, size_t d_size, const void *st, size_t s_size) {
if (s_size % sizeof(int) != 0) {
return -1; // bad struct size
}
size_t n = s_size / sizeof(int);
const char *delimiter = "";
for (size_t i = 0; i < n; i++) {
int d;
memcpy(&d, st, sizeof d);
st = (char*) st + sizeof(int);
int len = snprintf(dest, d_size, "%s%d", delimiter, d);
if (len < 0 || (size_t) len >= d_size) {
return -1; // out of room
}
dest += len;
d_size -= len;
delimiter = " ";
}
return 0;
}
struct s1 {
int VBUS_voltage_mV;
int temp_internal_degC;
int status;
...
};
struct s1 st = ...;
char buf[1024];
print_int_struct(buf, sizeof buf, &st, sizeof st);
puts(buf);

C - Passing structures through function arguments

I am asked to write a function that takes two values from the structure type and compare them. If they are equal, it wants me to add two other values from those structures and send this to another structure. It is also supposed to return a 1 or 0 through the functions name, so I defined the function as an int.
I have attempted to write a program that takes an employee's social security number and their wage, and then another employee's ssn and wage. If the socials are the same, it will combine the two wages and send them to another structure which contains that employees total wages.
I am getting errors every time I mention the function compare. This appears to be due to the arguments of the function. How can this be done properly?
#include <stdio.h>
#include <stdlib.h>
#define EMPLOYEE_COUNT 4
struct ewage
{
int ssn;
int wage;
}
struct record
{
int totalwage;
}
int compare(struct ewage s1, struct ewage s2, struct record *r);
int main (void)
{
struct ewage e[EMPLOYEE_COUNT];
struct record r[EMPLOYEE_COUNT];
int i, j;
for (i = 0; i < EMPLOYEE_COUNT; i ++)
{
for (j = i + 1; j < EMPLOYEE_COUNT; j ++)
{
int success = compare(e[i], e[j], &record[i]);
if (success == 1)
printf ("%d / %d | Record: %d \n", i, j, record[i]);
else
printf ("%d / %d | DOES NOT MATCH \n", i, j);
}
}
system ("PAUSE");
return 0;
}
int compare(struct ewage s1, struct ewage s2, struct record *r)
{
if (s1.ssn == s2.ssn)
{
r->totalwage = s1.wage + s2.wage;
return 1;
}
return 0;
}
You need semicolons after your struct defintion
struct ewage
{
int ssn;
int wage;
}; // here
struct record
{
int totalwage;
}; // here
record is not defined, I assume it's real name is r
int success = compare(e[i], e[j], &r[i]); // here
if (success == 1)
printf ("%d / %d | Record: %d \n", i, j, &r[i]); // here
Finally, you need something to print with the final %d, I assume total wage here:
printf ("%d / %d | Record: %d \n", i, j, r[i].totalwage); // here
Now you can start to debug it ...
there are a few mistakes:
1.there should be a ';' after the definition of a struct
2.you shouldn't pass a type 'record' to your function compare,instead you should pass &r[i]

exact multiple scanf input

I'm wondering on how to basically input exactly 5 numbers (integers specifically) in one line using simple commands such as while, if and arrays. For example:
if I input 5 numbers separated by spaces,
1 2 3 4 5
program would print
1 2 3 4 5
but, If I input less than 5 or more than 5,
1 2 3 4
program would print
invalid input.
So far I have
#include<stdio.h>
int main(int argc,char *argv[]){
int array[5], numbers;
numbers = 0;
while (numbers < 5) {
scanf("%d", &array[numbers]);
numbers = numbers + 1
}
printf("%d %d %d %d %d\n", array[0], array[1], array[2], array[3], array[4]);
return 0;
}
What about if we assign all the array cell with 9999 (a number not used by the program). And we make a loop to check that each array has been changed to a new value and if its still 9999 it would be invalid. But problem here still lies, how would we just grab one line of different number of input and move on. E.g input 2 3
Output 2 3 9999 9999 9999
Or input 2 3 4
Output 2 3 4 9999 9999
If you want to force the input to be on one line, first read the input and then parse it:
char line[100];
fgets(line, 100, stdin);
char x[100];
int n = sscanf(line, "%d %d %d %d %d %s", array, array+1, array+2, array+3, array+4, x)
if (n != 5)
printf("invalid input\n");
else
printf("read 5 numbers\n");
The x is added to detect if too much was read.
EDIT
To enter 5 numbers you may use
int a[5];
char x;
scanf("%d %d %d %d %d", &a[0], &a[1], &a[2], &a[3], &a[4]);
while(scanf("%*[^\n]%*c")) {
scanf("%c", &x); // after 5 ints were loaded, get rid of rest of the elements untill new line symbol
}
printf("%d %d %d %d %d\n\n", a[0], a[1], a[2], a[3], a[4]);
It will ignore everything after 5 numbers (in fact, it will write to x untill new line symbol appears), but there is no way to easily set number of numbers to read in this case.
You just have to note it will not work if you have less than 5 ints in line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int intRead(int array[], int size){
char buff[128];
int status=!0;//status == 0, Something happened!
printf("\ninput %d integer:", size);
while(fgets(buff, sizeof(buff), stdin)){
int count=0;
char*p;
for(p=buff;NULL!=(p=strtok(p, " \t\n"));p=NULL){
char *ck;
int i;
i=(int)strtol(p, &ck, 0);
if(*ck){
fprintf(stderr, "invalid input:can't parse of int <<%s>>\n", p);
status=0;
continue;
}
if(count < size){
array[count++]=i;
continue;
}
count = size + 1;//more than
break;
}
if(count < size)
fprintf(stderr, "invalid input: less than %d\n", size);
else if(count == size) return status;
if(count > size)
fprintf(stderr, "invalid input: more than %d\n", size);
printf("\ninput %d integer:", size);
status = !0;
}
return 0;
}
int main(int argc,char *argv[]){
int array[5];
intRead(array, 5);//or: while(!intRead(array, 5));
printf("%d %d %d %d %d\n", array[0], array[1], array[2], array[3], array[4]);
return 0;
}

Resources