Trying to parse string into struct members - c

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

Related

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

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

sscanf() double & string

I am fairly new to the world of programming so please forgive me if this is a common mistake.
I'm trying to scan 3 double values and 3 strings out of one input string but it doesnt continue after the second value.
double total_weight_kg(char *s, int Length) {
double weights[3];
char units[3];
int test = sscanf(s, "%lf, %s, %lf, %s, %lf, %s",
&weights[0], &units[0],
&weights[1], &units[1],
&weights[2], &units[2]);
printf("%i\n", test);
printf("%s\n", &units[0]);
int main(void) {
total_weight_kg("5, g, 1, t, 175, kg", 3);
return 0;
The first print prints out 2 and the second the g.
Furthermore I'd like to compare units[i] in a loop but can't seem to get that working either.
for (int i = 0; i < Length; i++) {
w = weights[i];
if (strcmp(units[i], "kg") == 0) {
weight += w;
}
}
I hope you can help me find a solution for this problem,
edit: Everyting is working as intended now. Thank you very much for your help. ( 19[^,] was one major problem )
There are some problems in your code:
To scan the strings into units, you must define it as a 2D array of char:
char units[3][20];
You should modify the scanf format to stop the word parsing on , and spaces, as suggested by user3386109.
Also modify the printf to pass the array instead of its address.
Here is the modified code:
double total_weight_kg(char *s, int Length) {
double weights[3];
char units[3][20];
int test = sscanf(s, "%lf, %19[^, \n], %lf, %19[^, \n], %lf, %19[^, \n]",
&weights[0], units[0],
&weights[1], units[1],
&weights[2], units[2]);
printf("%i\n", test);
printf("%s\n", units[0]);
...
}
int main(void) {
total_weight_kg("5, g, 1, t, 175, kg", 3);
return 0;
}

value in loop doesnt return

i have this data in file
ATOM 1 N MET A 1 25.909 16.164 -8.037
ATOM 2 CA MET A 1 25.498 14.786 -8.206
ATOM 3 C MET A 1 26.612 13.934 -8.806
ATOM 4 O MET A 1 27.442 14.402 -9.588
this is my full code
#include<stdio.h>
#include<math.h>
typedef struct prot {
char atom[10];
int atomno;
char site[10];
char residue[10];
char chain;
int residueno;
float x, y, z;
} Td;
int main()
{
FILE*fd;
fd=fopen("2zoi.pdb","r+");
Td data[1300];
char buffer[1300];
int a=0;
while(fgets(buffer, 1300, fd))
{
sscanf(buffer, "%s %d %s %s %c %d %f %f %f",data[a].atom,&data[a].atomno,data[a].site,
data[a].residue,&data[a].chain,&data[a].residueno,&data[a].x, &data[a].y, &data[a].z);
printf("%s %d %s %s %c %d %6.3f %6.3f %6.3f \n",data[a].atom,data[a].atomno,data[a].site,
data[a].residue,data[a].chain,data[a].residueno,data[a].x, data[a].y, data[a].z);
a++;
}
//---user input
int fr,sr;
int fa,sa;
int i=0;
float x1,x2,y1,y2,z1,z2;
float distance=0;
printf("Enter first no of atom :");
scanf("%d",&fa);
printf("Enter second no of atom :");
scanf("%d",&sa);
while(data[i].atomno>=0)
{
if(fa==data[i].atomno)
{
x1=data[i].x;
y1=data[i].y;
z1=data[i].z;
}
else if(sa==data[i].atomno)
{
x2=data[i].x;
y2=data[i].y;
z2=data[i].z;
}
i++;
}
printf("%f %f %f",x1,y1,z1);
printf("%f %f %f",x2,y2,z2);
//distance= sqrt(pow((x2 - x1), 2) + pow((y2 - y1), 2) + pow((z2 - z1), 2));
//printf("%6.3f",distance);
return 0;
}
the problem is at this part
printf("%f %f %f",x1,y1,z1);
printf("%f %f %f",x2,y2,z2);
i try to return to values from above loop where the value for x1,y1,z1 is for the first atom and x2,y2,z2 for second atom.
when i input 3 and 4, it gives answer
26.612 13.934 -8.806
27.442 14.402 -9.588
which is correct. but when i input 1 and 2, it gives rubbish answer. it seems like i cant input number 2 also number 10.did i do any mistake?
You have a big problem with data array values: not all elements of the array are set to 0 then the final loop can be broken.
You can use memset to reset to 0 all bytes of data array.
#include<stdio.h>
#include<math.h>
#include <string.h>
typedef struct prot
{
char atom[10];
int atomno;
char site[10];
char residue[10];
char chain;
int residueno;
float x, y, z;
} Td;
int main()
{
FILE*fd;
Td data[1300];
char buffer[1300];
size_t a=0;
fd=fopen("2zoi.pdb","r+");
if (fd != NULL)
{
memset(data, 0x00, sizeof(data));
while ((fgets(buffer, 1300, fd)) && (a < sizeof(data)/sizeof(data[0])))
{
sscanf(buffer, "%s %d %s %s %c %d %f %f %f",data[a].atom,&data[a].atomno,data[a].site,
data[a].residue,&data[a].chain,&data[a].residueno,&data[a].x, &data[a].y, &data[a].z);
printf("%s %d %s %s %c %d %6.3f %6.3f %6.3f \n",data[a].atom,data[a].atomno,data[a].site,
data[a].residue,data[a].chain,data[a].residueno,data[a].x, data[a].y, data[a].z);
a++;
}
//---user input
int fr,sr;
int fa,sa;
size_t i=0;
float x1,x2,y1,y2,z1,z2;
float distance=0;
printf("Enter first no of atom :");
scanf("%d",&fa);
printf("Enter second no of atom :");
scanf("%d",&sa);
while ((data[i].atomno>=0) && (i < sizeof(data)/sizeof(data[0])))
{
if(fa==data[i].atomno)
{
x1=data[i].x;
y1=data[i].y;
z1=data[i].z;
}
else if(sa==data[i].atomno)
{
x2=data[i].x;
y2=data[i].y;
z2=data[i].z;
}
i++;
}
printf("%f %f %f\n",x1,y1,z1);
printf("%f %f %f\n",x2,y2,z2);
}
else
{
fprintf(stderr, "Error opening file\n");
exit(1);
}
return 0;
}
You should check the fopen return value (as you can see in code posted), but as a standard rule: you should always check functions return values.

Print the nth member among five members’ height using Structure

#include <stdio.h>
struct member {
char name[20];
int age;
char sex;
int height;
};
int main(void)
{
int i,j;
struct member input[5]={0,};
int tot, rank, max=0;
int max2[5]={0,};
float res;
for (i=0; i<5; i++)
{
scanf("%s ", input[i].name);
scanf("%d %c %d", &input[i].age, &input[i].sex, &input[i].height);
getchar();
}
scanf("%d", &rank);
max =input[0].height;
for(i=1;i<=5;i++) {
for(j=0;j<5;j++) {
if(max>=input[j].height)
max=max;
else
max=input[j].height;
}
max2[i]=max;
for(j=0;j<5;j++) {
if(max==input[j].height)
input[j].height*=(-1);
}
max=-1;
}
for (i=0; i<5; i++)
{
if(max2[rank]== input[i].height)
printf("%s %d %c %d\n",input[i].name, input[i].age, input[i].sex,input[i].height);
}
fflush(stdin);
getchar();
return 0;
}
The result printed of above my code is nothing...Even the height inputted becomes negative number..
What's wrong with this program?
Input & Print should be the same like example image.......
please help!
The first scanf should be fixed
scanf("%s ", input[i].name);
In the second scanf, the input[i].sex is a char type so you have to use "%c" instead of %s
scanf("%d %s %d", &input[i].age, &input[i].sex, &input[i].height);
should be
scanf("%d %c %d", &input[i].age, &input[i].sex, &input[i].height);
You have a lot of problems here:
1) You're taking the wrong parameters from scanf():
scanf("%s ", input[i].name); // You don't need a & for a string
scanf("%d %c %d", &input[i].age, &input[i].sex, &input[i].height); // you need %c for a
// character
2) You're using for(i=1;i<=5;i++) to access an array of 5 elements, by doing this you're overflowing the array (it should be 0 to 4, not 1 to 5)
3) This is a nit-pick but:
if(max>=input[j].height)
max=max;
that is totally pointless. You don't need to set a variable to itself, just invert the logic (<) and only do the else case.
4) You set all the input[x].height's to the negative of the value they're originally set to here:
input[j].height*=(-1);
Then you check to see if that is the same as the original values which you stored in max2[] before printing here:
if(max2[rank]== input[i].height)
printf("%s %d %s %d\n",input[i].name, input[i].age, input[i].sex,input[i].height);
Well, that's never going to happen, so you'll never print anything
5) fflush(stdin); is not a well defined operation on most systems and could lead to undefined behavior, so don't do it.

Resources