Here is the code that is giving me the error of Segmentation fault..
void hire_skill()
{
int linec = 0;
FILE *p;
p = fopen("/home/suraj/Coding/PBL/Details/hiree.txt", "r");
if (p == NULL)
{
printf("\nFile did not open\n");
}
char c;
c = fgetc(p);
while (c != EOF)
{
if (c == '\n')
{
linec++;
}
c = fgetc(p);
}
fclose(p);
printf("\nNumber of lines :\t%d\n", linec);
FILE *ptrr;
ptrr = fopen("/home/suraj/Coding/PBL/Details/hiree.txt", "r");
if (ptrr == NULL)
{
printf("\nFile did not open\n");
}
rewind(ptrr);
for (int i = 0; i < linec; i++)
{
fscanf(ptrr, "%s", hiree_login[i].name);
fscanf(ptrr, "%d", hiree_login[i].age);
fscanf(ptrr, "%s", hiree_login[i].gender);
fscanf(ptrr, "%d", hiree_login[i].uid);
fscanf(ptrr, "%s", hiree_login[i].skill);
fscanf(ptrr, "%lld", hiree_login[i].phno);
}
for (int i = 0; i < linec; i++)
{
printf("\n%s, %d, %s, %d, %s, %lld\n", hiree_login[i].name, hiree_login[i].age, hiree_login[i].gender, hiree_login[i].uid, hiree_login[i].skill, hiree_login[i].phno);
}
fclose(ptrr);
}
And here is the structure i'm using to get values from the file and store it
struct hireeLogin
{
int age;
char name[20];
char gender[1];
int uid;
char skill[20];
long long int phno;
} hiree_login[MAX1]; //MAX1 = 50..
The whole code is on my github account : https://github.com/Suru-web/PBL/blob/main/Emp.c
I tried a few irrelevant things, but none of them worked. maybe i dont know much about this, so i would like anyone to help me fix my code. Thank you!!
gender is an array of size 1 and can therefore hold a string of up to length 0. In the line fscanf(ptrr, "%s", hiree_login[i].gender);, scanf is probably writing more than zero characters into the buffer, so the behavior is undefined.
Never use "%s" in a format string. Always use a width modifier that is no more than one less than the size of the buffer.
In this line ,
fscanf(p, "%s", hiree_login[i].name);
File pointer p is already closed. You may need to use ptrr
Related
I try to store input from a text file to an array of struct's elements
For example:
#001 Bulbasaur Grass Poison
#002 Ivysaur Grass Poison
#003 Venusaur Grass Poison
#004 Charmander Fire
#005 Charmeleon Fire
#006 Charizard Fire Flying
You can see that pokemons may have 2 types and some have only 1 type and the code went well until a pokemon that has only 1 type.
This a part of the output when I try to print the array of struct's elements:
#001 Bulbasaur Grass Poison
#002 Ivysaur Grass Poison
#003 Venusaur Grass Poison
#004 Charmander Fire #005
Charmeleon Fire #006 Charizard
Fire Flying #007 Squirtle
Water #008 Wartortle Water
#009 Blastoise Water #010
I tried a lot of things from checking a '\n' in the type1 buffer until searching web but I can't find a solution, please help me.
And BTW if I am doing something wrong with the dynamic memory allocation I would love to get suggestions.
These are the structs and the function:
typedef struct pokemon
{
int ID;
char *number;
char *name;
char *type1;
char *type2;
} Pokemon;
struct Trainer
{
char *firstName;
char *lastName;
Pokemon *pokemonsInBank;
Pokemon pokemonHeldByTheTrainer[6];
} Trainer;
struct pokemonDataBase
{
Pokemon *pokemonsDB;
int numOfPokemon;
} pokemonDataBase;
Storing Function
void loadPokemonsToDB()
{
char numBuffer[maxSize];
char nameBuffer[maxSize];
char typeBuffer[maxSize];
char type2Buffer[maxSize];
int i = 0;
char check[maxSize];
FILE *fp = fopen("Pokemons.txt", "r");
if (fp == NULL)
{
printf("Error opening the file\n");
exit(4);
}
pokemonDataBase.pokemonsDB = (Pokemon *)malloc((countPok()) * sizeof(Pokemon));
if (pokemonDataBase.pokemonsDB == NULL)
{
printf("Memory Error\n");
exit(4);
}
for (int i = 0; i < countPok(); i++)
{
fscanf(fp, "%s", numBuffer);
pokemonDataBase.pokemonsDB[i].number = (char *)malloc((strlen(numBuffer) + 1) * sizeof(char));
if (pokemonDataBase.pokemonsDB[i].number == NULL)
{
for (int j = 0; j < i; j++)
{
free(pokemonDataBase.pokemonsDB[j].number);
}
printf("Memory Error at index %d", i);
exit(4);
}
strcpy(pokemonDataBase.pokemonsDB[i].number, numBuffer);
fscanf(fp, "%s", nameBuffer);
pokemonDataBase.pokemonsDB[i].name = (char *)malloc((strlen(nameBuffer) + 1) * sizeof(char));
if (pokemonDataBase.pokemonsDB[i].name == NULL)
{
for (int j = 0; j < i; j++)
{
free(pokemonDataBase.pokemonsDB[j].name);
}
printf("Memory Error at index %d", i);
exit(4);
}
strcpy(pokemonDataBase.pokemonsDB[i].name, nameBuffer);
fscanf(fp, "%s", typeBuffer);
pokemonDataBase.pokemonsDB[i].type1 = (char *)malloc((strlen(typeBuffer) + 1) * sizeof(char));
if (pokemonDataBase.pokemonsDB[i].type1 == NULL)
{
for (int j = 0; j < i; j++)
{
free(pokemonDataBase.pokemonsDB[j].type1);
}
printf("Memory Error at index %d", i);
exit(4);
}
strcpy(pokemonDataBase.pokemonsDB[i].type1, typeBuffer);
fscanf(fp, "%s", type2Buffer);
pokemonDataBase.pokemonsDB[i].type2 = (char *)malloc((strlen(type2Buffer) + 1) * sizeof(char));
if (pokemonDataBase.pokemonsDB[i].type2 == NULL)
{
for (int j = 0; j < i; j++)
{
free(pokemonDataBase.pokemonsDB[j].type2);
}
printf("Memory Error at index %d", i);
exit(4);
}
strcpy(pokemonDataBase.pokemonsDB[i].type2, type2Buffer);
}
}
scanf is not your friend. A whitespace in the format string does not distinguish between space and newline. You can make scanf work, but it's really not worth the effort. I recommend you not do this, but you could try something like:
#include<assert.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct pokemon
{
int ID;
char name[128];
char type1[128];
char type2[128];
};
int
main(int argc, char **argv)
{
FILE *ifp = argc > 1 ? fopen(argv[1], "r") : stdin;
if( ifp == NULL ){
perror(argv[1]);
return 1;
}
struct pokemon poke[128];
struct pokemon *p = poke;
struct pokemon *e = poke + sizeof poke / sizeof *poke;;
int i = 0;
int rv;
while( p < e &&
2 < (rv = fscanf(ifp, " #%d %127s %127s %127[^\n]",
&p->ID,
p->name,
p->type1,
p->type2
)
)
){
assert( rv == 3 || rv == 4 );
if( rv == 3 ){
p->type2[0] = '\0';
}
p += 1;
}
e = p;
p = poke;
for( ; p < e; p++ ){
printf("%d %s %s %s\n", p->ID, p->name, p->type1, p->type2);
}
}
/* sample of expected input
#001 Bulbasaur Grass Poison
#002 Ivysaur Grass Poison
#003 Venusaur Grass Poison
#004 Charmander Fire
*/
Note that this is extremely fragile. If a row contains 10 "words", the remainder will all go into the type2 field. Also, as soon as you have a name that exceeds the 127 character length, parsing will just stop and not give any indication as to why. Handling unruly input is just not easy to do with scanf, and it's generally not worth the effort. Maybe a simple:
if( ! feof(ifp) ){
fprintf(stderr, "invalid input\n");
exit(1);
}
after the input loop would be sufficient, but it would be better to simply stop trying to use scanf. In the end, you will waste a lot of time trying to figure its behavior, and that time would be better spent learning how to use other tools to parse the input.
If you want to minimize changes to your existing code, you could try adding something like the following before you attempt to scan into the second type:
int c;
while( ( c = getc(ifp) ) == ' ' ){
;
}
if( c != '\n' ){
ungetc(c, ifp);
/* Scan the second word */
} else {
/* There is no second word */
}
Note that mixing scanf with getc is a potential source of confusion, and if you don't know exactly what you're doing this can cause great frustration. The basic idea is to consume spaces until you see a non-space (note that the above code will need to be modified if you want to handle tabs or other non-newline whitespace). If the first character you see is a newline, simply move on to the next line. If it is not a newline, put it back on the stream so scanf can see it and read the second type. Again, this cannot be stated often enough, you should abandon scanf now. It will cause you far more headaches than it is worth.
Im trying to read a text file into an array of structs, but when trying to print the array, the struct is empty. The printing function works fine and I think the problem is in getRawData.
struct student
{
char ID[MAXID + 1];
char f_name[FIRST_NAME_LENGTH + 1];
char s_name[LAST_NAME_LENGTH + 1];
int points[MAXROUNDS];
};
//main//
case 'W':
if(save(array, len) == 0);
{
printf("Data saved.\n");
}
break;
case 'O':
if(getRawData(array, len));
{
printf("File read.\n");
}
break;
int save(struct student *h, int num_students)
{
char name[20];
printf("Enter file name: " );
scanf("%s", name); // Read in filename
FILE *output = fopen(name, "w"); // open the file to write
if (!output) {
return -1; // error
}
for (int i = 0; i < num_students; ++i)
{
fprintf(output, "%s %s %s \n", h[i].f_name, h[i].s_name, h[i].ID);
for(int j = 0; j < MAXROUNDS; j++)
{
fprintf(output, "%d\n", h[i].points[j]);
}
printf("Information of student %s %s (%s) written into file %s\n", h[i].s_name, h[i].f_name, h[i].ID, name);
}
fclose(output); // close
return 0;
}
int getRawData(struct student *records)
{
int i;
int nmemb; // amount of structs
char name[20];
printf("Name of the file to be opened: \n");
scanf("%s", name);
FILE *outtput = fopen(name, "r");
int ch=0;
int lines=0;
if (outtput == NULL);
return 0;
lines++;
while(!feof(outtput))
{
ch = fgetc(outtput);
if(ch == '\n')
{
lines++;
}
}
nmemb = lines / 7;
for(i = 0; i < nmemb; i++) {
fscanf(outtput, "%s %s %s", records[i].f_name, records[i].s_name, records[i].ID);
for(int j = 0; j < MAXROUNDS; j++)
{
fscanf(outtput, "%d\n", &records[i].points[j]);
}
}
printf("%d", lines);
return i;
}
So my goal is to get the data from the file and write it over whatever there is stored in the struct array. I would appreciate some help as I have been working on this for way too long.
Look at this code in getRawData(), first you are reading file to identify total number of lines:
while(!feof(outtput))
{
ch = fgetc(outtput);
if(ch == '\n')
.....
.....
due to this the file stream pointer pointing to EOF and after this, in the for loop, you are doing:
for(i = 0; i < nmemb; i++) {
fscanf(outtput, "%s %s %s", records[i].f_name, records[i].s_name, records[i].ID);
.....
.....
Here, the fscanf() must be returning the EOF because there is nothing remain to read from stream file. You should check the return value of fscanf() while reading file.
You should reset the pointer to start of file before reading it again. You can use either rewind(ptr) or fseek(fptr, 0, SEEK_SET). Below is a sample program to show you what is happening in your code and how the solution works:
#include <stdio.h>
int main (void) {
int ch;
int lines = 0;
char str[100];
FILE *fptr = fopen ("file.txt", "r");
if (fptr == NULL) {
fprintf (stderr, "Failed to open file");
return -1;
}
while (!feof(fptr)) {
ch = fgetc (fptr);
if(ch == '\n') {
lines++;
}
}
printf ("Number of lines in file: %d\n", lines);
printf ("ch : %d\n", ch);
printf ("Now try to read file using fscanf()\n");
ch = fscanf (fptr, "%s", str);
printf ("fscanf() return value, ch : %d\n", ch);
printf ("Resetting the file pointer to the start of file\n");
rewind (fptr); // This will reset the pointer to the start of file
printf ("Reading file..\n");
while ((ch = fscanf (fptr, "%s", str)) == 1) {
printf ("%s", str);
}
printf ("\nch : %d\n", ch);
fclose (fptr);
return 0;
}
The content of file reading in the above program:
Hello Vilho..
How are you!
Output:
Number of lines in file: 2
ch : -1
Now try to read file using fscanf()
fscanf() return value, ch : -1
Resetting the file pointer to the start of file
Reading file..
HelloVilho..Howareyou!
ch : -1
Here you can see, the first ch : -1 indicate that the file pointer is at EOF and if you try to read you will get EOF because there is nothing left to read. After resetting file pointer, you can see fscanf() is able to read file.
You should not use while (!feof(file)). Check this.
I am trying to read a line from a file using fscanf():
#include<stdio.h>
#include<stdlib.h>
int main()
{
FILE *fp;
char c, *string[4];
int i = 0,j[4];
fp = fopen("boil.txt", "r");
c = fgetc(fp);
if(fp == NULL)
{ printf("File read error\n");
exit(0);
}
while(c != '\n')
{
fscanf(fp, "%s %d ", string[i] , &j[i]);
i++;
c = fgetc(fp);
}
for(i = 0; i < 4; i++)
{
printf("%s %d\n", string[i], j[i]);
}
}
boil.txt is as follow:
boil 4 boilmilk 3 boilwater 5 heat 10
Why this program is giving Segmentation Fault?
Because you don't reserve space for such strings:
char *string[4];
is an array of pointers to string, but you need room to store those strings, something like:
char temp[256];
fscanf(fp, "%s %d ", temp , &j[i]);
string[i] = strdup(temp);
EDIT:
As pointed out by iRove, strdup is not part of the standard (but available on many implementations), if you can't use strdup, an alternative is:
string[i] = malloc(strlen(temp) + 1);
if (string[i] == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
strcpy(string[i], temp);
Don't forget to call free at the end (when the strings are no longer needed)
for (i = 0; i < 4; i++) free(string[i]);
I was writing a program to read hexcodes from a file and feed it to another chip via SPI. I am trying to read each line from the hexfile using fgets and then parse it using sscanf into a unsinged int array The format of the hexfile is as follows:
ff32
34dc
1234
32d4
....
int main (void)
{
FILE *fp1;
int i = 0;
fp1 = fopen("hexfile.txt", "r+");
char line[500];
unsigned int hex[40];
while (fgets(line, sizeof(line), fp1) != NULL) {
while (sscanf(line, "%x", &hex[i]) == 1) {
printf("%4x \n", hex[i]);
i++;
}
}
fclose(fp1);
return 0;
}
Error: Segmentation Fault (core dumped) Which I know roughly results when you try to dereference a NULL pointer. But what is wrong with my code? Second, is there a better way to read from a file using other File I/O functions without dynamic memory allocation?
You need to remove the while and replace it with if:
FILE *fp1;
int i = 0;
fp1 = fopen("d:\hexfile.txt", "r+");
char line[500];
unsigned int hex[40];
while (fgets(line, 8, fp1) != NULL) {
if (sscanf(line, "%x", &hex[i]) == 1) { /*here while => if */
printf("%4x \n", hex[i]);
i++;
}
}
fclose(fp1);
This loop will repeat for ever or until writing to hex[i] breaks something
while (sscanf(line, "%x", &hex[i]) == 1) {
In answer to OP's second question, here is another way
#include <stdio.h>
int main()
{
FILE *fp1;
int i = 0, j;
unsigned int hex[40];
fp1 = fopen("hexfile.txt", "rt");
while (i<40 && fscanf (fp1, "%x", &hex[i]) == 1)
i++;
fclose(fp1);
for (j=0; j<i; j++) // check
printf("%4x \n", hex[j]);
return 0;
}
I am getting a segmentation fault when I call my getField(char *line, int field) function in my while loop and I'm not sure why. I'm trying to pass a line to the function and a column number so that I can grab specific columns from each line in a csv file and print them to the screen. Thanks for input.
void getField(char *line, int field);
int main(int argc, char *argv[]) {
if(argc < 3) {
fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
}
if(atoi(argv[1]) < 1) {
fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
}
FILE *fp = fopen(argv[2], "r");
if(fp == NULL)
fprintf(stderr, "Cannot open file %s\n", argv[0]);
char buf[80];
while(fgets(buf, 80, fp) != NULL) {
getField(buf, atoi(argv[1]); // seg fault is happening here
}
return 0;
}
void getField(char *line, int field) {
printf("here2");
//char *ln = line;
int column = field - 1;
int idx = 0;
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
}
for(int j = idx; ; ++j) {
if(line[j] == ',') break;
printf("%s", line[j]);
}
printf("\n");
printf("%d", idx);
}
One obvious error is that you have an infinite loop here, and you will eventually access illegal memory.
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
}
You are not modifying column at all, so your loop cannot possibly end.
column will not update itself when you update field, so you will have to update it if you want it to update.
while(column) {
//printf("here");
if(line[idx] == ',') field--;
idx++;
column = field - 1;
}
Note on debugging segfaults using printf.
The function printf prints to stdout and stdout likes to buffer output. This means that sometimes if you try to find a segfault by moving a print statement down your code until it fails to print, you will misunderstand where the segfault it happening. In particular, a printf line that appears before the line that actually contains the segfault may not print even if you might expect it to.
If you want to use this strategy (instead of gdb), you can force it to print by using fflush(stdout); immediately after your debugging printf.
while(column) {
//printf("here");
if(line[idx] == ',') column--; // Changed field-- to column--
idx++;
}
In following line:
printf("%s", line[j]);
you are using the %s format specifier but you are passing a char as argument.
You probably want this (%c format specifier fot printing a char):
printf("%c", line[j]);
You are accessing out of bounds of the array in the function getField because the while loop never exits. This invokes undefined behaviour and most likely program crash due to segfault which is what is happening in your case. I suggest the following changes to your program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void getField(char *line, int field);
int main(int argc, char *argv[]) {
if(argc < 3) {
fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
return 1; // end the program
}
if(atoi(argv[1]) < 1) {
fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
return 1; // end the program
}
FILE *fp = fopen(argv[2], "r");
if(fp == NULL) {
fprintf(stderr, "Cannot open file %s\n", argv[0]);
return 1; // end the program
}
char buf[80];
while(fgets(buf, 80, fp) != NULL) {
getField(buf, atoi(argv[1])); // seg fault is happening here
}
return 0;
}
void getField(char *line, int field) {
int len = strlen(line);
char temp[len + 1];
strcpy(temp, line);
int count = 0;
char ch = ',';
char *p = temp;
char *q = NULL;
while(count < field - 1) {
q = strchr(p, ch);
if(q == NULL) {
printf("error in the value of field\n");
return;
}
count++;
p = q + 1;
}
q = strchr(p, ch);
if(q != NULL)
*q = '\0';
else
temp[len-1] = '\0';
printf("%s\n", p);
}