Printing the data in multiple structs - c

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);

Related

Trying to parse string into struct members

I have the following members in a struct:
typedef struct rect RECTANGLE;
struct rect
{
char command[16];
int width;
int height;
int x;
int y;
};
i want to parse the following input string into above struct:
new 3,4+7,8
For now i have the following code:
printf("Command input? ");
scanf("%15[^,]%d,%d+%d,%d",
new_rect.command,
atoi(&new_rect.height),
atoi(&new_rect.width),
atoi(&new_rect.x),
atoi(&new_rect.y));
printf("Command: %i\n", new_rect.command);
printf("Height: %i\n", new_rect.height);
printf("Width: %i\n", new_rect.width);
printf("x: %i\n", new_rect.x);
printf("y: %i\n", new_rect.y);
The code's %15[^,] will read up to the first comma, i.e. "new 3" which isn't what you want. Also you need to read the comma which terminates %15[^,] or the subsequent %d will fail. And always check the return value from scanf() which should have been 5.
Assuming that the command is a single word, this code seems to do the job. There was also an error in %s being %i for a string in the first printf
#include <stdio.h>
struct rect
{
char command[16];
int width;
int height;
int x;
int y;
} new_rect;
int main(void){
if(scanf("%15s%d ,%d +%d ,%d", new_rect.command, &new_rect.height, &new_rect.width, &new_rect.x, &new_rect.y) == 5) {
printf("Command: %s\n", new_rect.command);
printf("Height: %i\n", new_rect.height);
printf("Width: %i\n", new_rect.width);
printf("x: %i\n", new_rect.x);
printf("y: %i\n", new_rect.y);
}
return 0;
}
If have added some extra spaces in the format string to make it more tolerant of spaces that might be input. That's not necessary before %d, which filters whitespace anyway.
Running the program with the input shown gives
new 3,4+7,8
Command: new
Height: 3
Width: 4
x: 7
y: 8

Is it possible to use a for-loop in C to determine which value is the smallest among those inputted by user without using arrays?

I'm in the process of writing a C program that, at one point, asks the user to enter 10 positive whole numbers (integers) and prints the smallest number among those 10. This section of the program cannot include the use of arrays and must include the use of a for-loop. I'm stuck because, as far as I know, it's impossible to change variable names dynamically in C. Here is what I have thus far:
int main()
{
int value1, value2, value3, value4, value5, value6, value7, value8, value9, value10;
printf("Enter 10 positive integers.\n");
scanf("%i %i %i %i %i %i %i %i %i %i", &value1, &value2, &value3, &value4, &value5, &value6, &value7, &value8, &value9, &value10);
return 0;
}
I'm new to C so any help with the rest of the code would be greatly appreciated.
Simple example
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int minimum;
printf("Input 10 space separated integers\n");
if (scanf("%d", &minimum) != 1) exit(EXIT_FAILURE);
for (int j = 0; j < 9; j++) {
int value;
if (scanf("%d", &value) != 1) exit(EXIT_FAILURE);
if (value < minimum) minimum = value;
}
printf("minimum value entered was %d.\n", minimum);
}
Not in the manner you have written it.
If you were getting input one by one then you could keep a running track of what's the min value you have seen so far.
Yes it is possible, making use of the fact that there is little-to-no difference between arrays and pointers to arrays in C. Basically you get a pointer to the first variable and then iterate through them, just like as if it was an array. The only thing to watch out for is to guarantee a known alignment of your variables. To achieve that, you have to put them in a struct.
I wasn't sure if your requirement was to only avoid the declaration of an array or completely avoid array syntax, so I avoided array syntax in the example below:
#include <stdio.h>
int main()
{
struct {
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
} inputs;
printf("Enter 10 positive integers.\n");
scanf("%i %i %i %i %i %i %i %i %i %i", &inputs.v1, &inputs.v2, &inputs.v3, &inputs.v4, &inputs.v5, &inputs.v6, &inputs.v7, &inputs.v8, &inputs.v9, &inputs.v10);
const int numItems = 10; // how many inputs do we have
int *ptr = &inputs.v1; // get pointer to first input
int smallest = *ptr; // initialize our result before calculation
++ptr; // increment pointer to second element
for (int i = 1; i < numItems; ++i) // we start from the second element so we start start counting from 1
{
// Smallest element calculation
if (*ptr < smallest)
smallest = *ptr;
++ptr;
}
printf("Smallest number: %i.\n", smallest);
return 0;
}
Here is a nicer looking version with array syntax (but still not using arrays):
#include <stdio.h>
int main()
{
struct {
int v1, v2, v3, v4, v5, v6, v7, v8, v9, v10;
} inputs;
printf("Enter 10 positive integers.\n");
scanf("%i %i %i %i %i %i %i %i %i %i", &inputs.v1, &inputs.v2, &inputs.v3, &inputs.v4, &inputs.v5, &inputs.v6, &inputs.v7, &inputs.v8, &inputs.v9, &inputs.v10);
const int numItems = 10; // how many inputs do we have
int* ptr = &inputs.v1; // get pointer to first input
int smallest = ptr[0]; // initialize our result before calculation
for (int i = 1; i < numItems; ++i) // we start from the second element so we start start counting from 1
{
// Smallest element calculation
if (ptr[i] < smallest)
smallest = ptr[i];
}
printf("Smallest number: %i.\n", smallest);
return 0;
}

Got some segmentation error when use struct pointer in for loop in C

Here is some simple code that prints struct values
in_hotel_info function is used to get struct inputs.(And yes, I use 'gets' because my professor forced me to use it sadly). And also When I put "0" as an input, it ends and returns its input numbers.
And I used sscanf to scan strings and numbers.
#include <stdio.h>
typedef struct hotel_info hotel;
struct hotel_info
{
char name[30];
int rank;
double popular;
double far;
char breakfast;
};
int in_hotel_info(struct hotel_info *p);
void out_hotel_info(struct hotel_info *p, int N, int G, double D);
int main(void)
{
hotel hotels[100];
hotel *p;
int number = 0, ranks, fars, i;
number = in_hotel_info(hotels);
p = hotels;
printf("%d\n", number);
getchar();
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
}
int in_hotel_info(struct hotel_info infos[])
{
char inputs[100];
hotel* p;
p = infos;
int cnt = 0;
while (1)
{
gets(inputs);
if (strcmp(inputs, "0") == 0)
{
break;
}
else
{
sscanf(inputs, "%s %d %lf %lf %c", p->name, &p->rank, &p->popular, &p->far, &p->breakfast);
}
p++;
cnt++;
}
return cnt;
}
The problem is, when I tried to print
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
what I expected is
mike 2 3.5 4.24 Y
but I constantly got a segmentation error.
The problem is, when I tried to print
for (; p < p+number; p++)
{
printf("%s %d %lf %lf %c\n", p->name, p->rank, p->popular, p->far, p->breakfast);
}
the problem is p < p+number is always true when number is strictly positive, so the for never ends and you access out of the array with an undefined behavior (your segmentation fault).
you have additional problems
gets is very dangerous to use because it can write out of the array, use fgets or scanf (secifying max length to read), in the considered case you can read a number then check if it is 0 or not
in in_hotel_info in case the user enter more than than entrie you write out of the array, you need to get the max number of element to read in argument
when you read p->name in case the enter name longer than 29 you write out of the array, limit the size using %29s rather than %s. ALso to bypass spaces at the beginning of the name use %29s (with a space before)
you do not check scanf returns 5, so you do not detect invalid inputs
The getchar(); in main is strange

Scanning multiple line data from .txt file into struct array

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.

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]

Resources