Segmentation fault while printing first element of string array in c - c

I am scanning lines from a textfile and putting elements into specific arrays, sscanf is working fine and inserting variables into arrays as well BUT printing out first element of string array result in segmentation fault(printing works for first elements from other arrays and for rest elements in string array)
Here is my code:
char **shipTable = NULL;
char *notimportant;
double *dirTable;
double *numTable;
double *speedTable;
double *latTable;
double *lngTable;
void scanShips(){
char fname[30];
char line[150];
char shipname[10];
double lat;
double lng;
double speed;
double dir;
int numofShips;
numofShips=1;
FILE *myfile;
printf("give file name containing ships /n");
scanf("%s",fname);
myfile = fopen(fname,"rt");
fgets(line,80,myfile);
sscanf(line, "%d %d %d %d %d %d", &day, &month, &year, &h, &min, &sec);
while ( fgets( line,100,myfile) != 0 ) {
sscanf(line, "%s %lf %lf %lf %lf", shipname, &lat, &lng, &dir, &speed);
printf("%s",shipname);
printf("\n");
shipTable = realloc( shipTable, numofShips*sizeof(char*) );
latTable = realloc( latTable, numofShips*sizeof(double) );
lngTable = realloc( lngTable, numofShips*sizeof(double) );
dirTable = realloc( dirTable, numofShips*sizeof(double) );
speedTable = realloc( speedTable, numofShips*sizeof(double) );
shipTable[numofShips-1]=malloc((10)*sizeof(char));
strcpy (shipTable[numofShips-1],shipname);
dirTable[numofShips-1]=dir;
speedTable[numofShips-1]=speed;
latTable[numofShips-1]=lat;
lngTable[numofShips-1]=lng;
numofShips++;
//printf("%d",numofShips);
}
fclose ( myfile);
//note:
printf("%s",shipTable[0]);//<---Segmentation fault
printf("%s",shipTable[1]);//<---Perfectly fine, as well as rest fo the array
printf("%f",dirTable[0]);//<---Perfectly fine, as well as rest of "double" arrays
Example file :
13 11 2011 13 04 00
GW1927 52.408 -4.117 1.000 0.000
GS452 51.750 -4.300 5.000 10.000
EI597 52.100 -6.000 90.000 12.000
EI600 52.000 -5.900 10.000 15.000
EI601 54.000 -5.900 10.000 15.000
Shipname length will never be longer than 9 chars.

Your program is incomplete. Once I make it complete (by adding necessary #includes, defining day, month, etc.), it compiles and works just fine.
Conclusion: you are not telling us the whole story, and the bug is in the code that you didn't show.

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

Trouble getting sscanf to work correctly with certain inputs

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",

sscanf not scanning in the elements from string properly

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;

(C) Reading from a Text File to a Structure

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.

Parsing data from ASCII formatted file in C

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

Resources