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
I'm trying to read the values in those lines to the variables with sscanf and I'm getting very weird results. It works with some lines as long as I use floats, but with other similar lines with floats it doesn't work, and if I use doubles instead of floats it never works properly.
#include <stdio.h>
#include <stdlib.h>
void debug(char* line,int* year, int* month, int* day, double* temp, double* uncertainty,
char country[100]){
int result;
result = sscanf(line, "%i - %i - %i, %lf , %lf , %s", year,
month, day, temp, uncertainty, country);
printf("%i-%i-%i,%f,%f,%s\n",*year, *month, *day, *temp,
*uncertainty, country);
printf("Result:%i\n", result);
}
void debug_f(char* line, int* year, int* month, int* day, float* temp, float* uncertainty,
char country[100]){
int result;
result = sscanf(line, "%i - %i - %i, %f , %f , %s", year,
month, day, temp, uncertainty, country);
printf("%i-%i-%i,%lf,%lf,%s\n",*year, *month, *day, *temp,
*uncertainty, country);
printf("Result:%i\n", result);
}
int main(){
char* error = "1943-09-01,29.27,0.403,Yemen";
char* working = "1972-03-01,4.787,0.342,Slovakia";
int year1, year2, year3, year4;
int month1, month2, month3, month4;
int day1, day2, day3, day4;
double temp1, temp2;
double uncertainty1, uncertainty2;
float temp3, temp4;
float uncertainty3, uncertainty4;
char country1[100], country2[100], country3[100], country4[100];
debug(error, &year1, &month1, &day1, &temp1, &uncertainty1, country1);
debug(working, &year2, &month2, &day2, &temp2, &uncertainty2, country2);
debug_f(error, &year3, &month3, &day3, &temp3, &uncertainty3, country3);
debug_f(working, &year4, &month4, &day4, &temp4, &uncertainty4, country4);
}
This is the output I get on my machine:
1943-0-0,0.000000,0.000000,�\��
Result:2
1972-3-1,0.000000,0.000000,Slovakia
Result:6
1943-0-0,0.000000,0.000000,
Result:2
1972-3-1,4.787000,0.342000,Slovakia
Result:6
Try removing the space used in between date elements in sscanf.
sscanf(line, "%i-%i-%i, %f , %f , %s",
&int1, &int2,
&int3, &double1, &double2,
s);
As EugeneSh pointed above its signed integer, and reading float to a double.
"%i" differs from "%d" when scanning
"1943-09-01,29.27,0.403,Yemen"; fails because "09" is not scanned into an int as 9 with "%i".
In the below code, when scanning for month, sscanf(), using "%i", encounters "09". Since it leads with a'0', that switches interpretation to octal. As '9' is not an octal digit, month is assigned 0 and scanning continues with " - %i, %lf , %lf , %s". Since '9' does not match '-', scanning stops and reports 2 successful conversions.
sscanf(line, "%i - %i - %i, %lf , %lf , %s", year, month, day, temp, uncertainty, country);
Suggested alternative
Use "%d" instead of "%i" to insure decimal interpretation.
Use width limits when saving a string.
Use "%n" to detect end of scan and look for extra junk.
void debug(const char* line, int* year, int* month, int* day,
double* temp, double* uncertainty, char country[100]){
int n = 0;
int result = sscanf(line, "%d - %d - %d , %lf , %lf , %99s %n",
year, month, day, temp, uncertainty, country, &n);
printf("Result:%i\n", result);
if (n > 0 && line[n] == '\0') {
printf("%i-%i-%i,%f,%f,%s\n",
*year, *month, *day, *temp, *uncertainty, country);
} else {
printf("<%s> failed\n", line);
}
}
Note that %s will not fully read country names like "Sri Lanka", but only the first "word" "Sri". Depending on coding goals, consider:
int result = sscanf(line, "%d - %d - %d , %lf , %lf , %99[^\n] %n",
I have created the following program
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
const double PI = 3.14159;
int main()
{
char str[120];
double distance, azimuth;
double delta_x = 0;
double delta_y = 0;
FILE *fp = fopen("input.txt", "r");
if (fp == NULL)
return -1;
fgets(str, sizeof(str), fp); //skip first line
while (fgets(str, sizeof(str), fp)) {
if (strcmp("Dig here!", str) == 0)
break;
printf(str);
sscanf(str, "go %f feet by azimuth %f\n", &distance, &azimuth);
printf("distance %f azimuth %f\n", distance, azimuth);
delta_y += distance * sin(azimuth * (PI/180));
delta_x += distance * cos(azimuth * (PI/180));
}
printf("%d %d", delta_x, delta_y);
fclose(fp);
return 0;
}
input.txt looks something like this
Stand at the pole with the plaque START
go 500 feet by azimuth 296
go 460 feet by azimuth 11
Dig here!
However the output gives
go 500 feet by azimuth 296
distance 0.000000 azimuth 0.000000
I'm sure it's a dumb error I am missing but I can't seem to find it, any help would be appreciated.
The "%f" format specifier of scanf is for float type:
f – Matches an optionally signed floating-point number; the next pointer must be a pointer to float.
If you wish to parse a double type then use the l format specifier in combination with f:
l – Indicates either that the conversion will be one of d, i, o, u, x, X, or n and the next pointer is a pointer to a long int or unsigned long int (rather than int), or that the conversion will be one of e, f, or g and the next pointer is a pointer to double (rather than float).
So, you should change your format string as follows:
sscanf(str, "go %lf feet by azimuth %lf\n", &distance, &azimuth);
printf("distance %lf azimuth %lf\n", distance, azimuth);
Note that fgets may contain trailing '\n', in other words if a newline is read, it is stored into the buffer. Therefore before you compare the input coming from fgets against "Dig here!", you have to remove the newline first.
There is many options to do this, in the comments below you can see a good one or you can use the following approach with strcspn function:
str[strcspn(str, "\r\n")] = '\0'; /* works for any combination of CR and LF */
if(strcmp("Dig here!", str) == 0)
break;
I am trying to read multiple different data types (char, int, float) from a text file directly into a Structure.
readData() {
char filename[100];
int linesread;
int i = 0;
printf("Enter the assets text file that you wish to read: \n");
scanf("%s", filename);
if ((fp = fopen(filename, "r")) == NULL) {
printf("Error opening data file\n");
readData();
} else {
while (fscanf(fp, "%s %c %s %lf %lf %d %d %d", &assets[i].name, &assets[i].type, &assets[i].location, &assets[i].longi, &assets[i].lati, &assets[i].speed, &assets[i].fuelTime, &assets[i].readyTime != EOF)) {
i++;
}
}
fclose(fp);
linesread = i;
for (i = 0; i < linesread; i++) {
printf("%s %s %s %lf %lf %d %d %d\n", &assets[i].name, &assets[i].type, &assets[i].location, &assets[i].longi, &assets[i].lati, &assets[i].speed, &assets[i].fuelTime, &assets[i].readyTime);
}
This Should read this out (when it decides to co-operate) and save it into the structure:
Angle_Lifeboat L Angle 51.685 -5.102 25.0 600 120
Angle_ILB L Angle 51.685 -5.102 25.0 180 30
Broad_Haven_ILB L Broad_Haven 51.713 -5.113 25.0 180 30
But instead reads this
ngle_Lifeboat LAngle Angle 0.000000 0.000000 0.000000 4231936 4231940
Angle_ILB LAngle Angle 0.000000 0.000000 0.000000 4232008 4232012
Broad_Haven_ILB LBroad_Haven Broad_Haven 0.000000 0.000000 0.000000 4232080 4232084
I am pretty new to C, so go easy on me. Any help you can give would be massively appreciated
EDIT: Stucture -->
typedef struct assets{
char name[25];
char type[1];
float longi;
float lati;
char location[20];
int speed;
int fuelTime;
int readyTime;
} assets;
In c programming i do think there is already an in build function to do the above ...
try using fread http://www.tutorialspoint.com/c_standard_library/c_function_fread.htm
fread(&my_struct, sizeof(my_struct), 1, fp);
BLUEPIXY correctly noticed the != EOF bad position; correct is:
… &assets[i].readyTime) != EOF) {
We cannot print the character in assets[i].type as a string with %s, because that 1-char-array type[1] doesn't have (room for) the terminating null character; we must print it as a string with precision .1 or a character:
printf("…%.1s…\n", …assets[i].type…); // need no & operator
or
printf("…%c…\n", …*assets[i].type…); // need * operator
The conversion specification %lf is for a pointer to double (rather than float); the floats need the conversion specification %f.
Since the speed values are 25.0, we cannot read them as integers with %d; we rather need to read a float variable with %f, either a temporary variable which is then assigned to assets[i].speed, or by defining float speed; in assets.
I am trying to do what's been done here Read co-ordinates from a txt files using C Program . The data that I am trying to input is in this format:
f 10 20 21
f 8 15 11
. . . .
f 11 12 25
The only difference in my point structure is that I have a an extra char to store the letter in the first column (which may or may not be the letter f). I guess im either declaring my char wrong, or I'm calling it in printf incorrectly. Either way, I only get the first line read and then my program terminates. Any ideas ?
Here is my MWE below
#define FILEPATHtri "/pathto/grid1DT.txt"
#define FILEPATHorg "/pathto/grid1.txt"
#define MAX 4000
#include <stdio.h>
#include <stdlib.h>
#include "math.h"
typedef struct
{
float x;
float y;
float z;
char t[1];
}Point;
int main(void) {
Point *points = malloc( MAX * sizeof (Point) ) ;
FILE *fp ;
fp = fopen( FILEPATHtri,"r");
int i = 0;
while(fscanf(fp, "%s %f %f %f ", points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
i++;
}
fclose(fp);
int n;
for (n=0; n<=i; n++){
printf("%c %2.5f %2.5f %2.5f \n", points[i].t, points[n].x, points[n].y, points[n].z ); }
printf("There are i = %i points in the file \n And I have read n = %i points ",i,n);
return 0;
}
Since there's only 1 char in there, not a string just use a single char in your code:
char t;
}Point;
Then when you read it in:
while(fscanf(fp, "%c %f %f %f ", &points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
I'll note that having an array of 1 char, at the end of a structure, sets you up for the struct hack which might not have been your intentions... A good reason to use just char t instead of char t[1]
Also this line:
for (n=0; n<=i; n++){
Should be
for (n=0; n<i; n++){
One last note... if you wanted to print the character out that you read in the prints at the bottom, you should be using n:
// note your previous code was points[i].t
printf("%c %f %f %f \n", points[n].t, points[n].x, points[n].y, points[n].z ); }
Check this
while(fscanf(fp, "%c %f %f %f ", points[i].t, &points[i].x, &points[i].y, &points[i].z ) == 4 )
{
i++;
}
fclose(fp);
int n;
for (n=0; n<i; n++){
printf("%c %2.5f %2.5f %2.5f \n", points[n].t, points[n].x, points[n].y, points[n].z ); }
printf("There are i = %i points in the file \n And I have read n = %i points ",i,n);
getch();
return 0;
}
modification are since only a single character is read %s modified to %c also in printf its not points[i].t its points[n].t . Also the limit checking in for loop is also corrected to n<i