*updated with how i stored the string into my struct
I have a struct as below:
struct patient {
char name[30], ID[8];
int age, phoneNo;
};
and i've written the following code:
int searchName()
{
char search[30];
char record[60];
const char s[2] = ",";
struct patient c;
char a[8];
int IDno;
FILE* fPtr;
fPtr = fopen("patient.txt", "r");
printf("Enter name to search : ");
getchar();
fgets(search, 30, stdin);
//remove the '\n' at the end of string
search[strcspn(search, "\n")] = 0;
while (fgets(record, 60, fPtr))
{
// strstr returns start address of substring in case if present
if (strstr(record, search))
{
char* pStr = strtok(record, ",");
if (pStr != NULL) {
strcpy(c.ID, pStr);
}
pStr = strtok(NULL, ",");
if (pStr != NULL) {
strcpy(c.name, pStr);
}
pStr = strtok(NULL, ",");
if (pStr != NULL) {
c.age = atoi(pStr);
}
pStr = strtok(NULL, ",");
if (pStr != NULL) {
c.phoneNo = atoi(pStr);
}
}
}
printf("%s", c.ID);
strcpy(a, c.ID);
printf("\n%s", a);
IDno = atoi(a);
printf("\n%d", IDno);
return 0;
}
the code allows me to search for a string in a file, separate the string into smaller strings using strtok, then store them into the struct. suppose i stored a string "PT3" into c.ID in the struct. in my program, I am trying to copy the string of "PT3" from c.ID to a, then convert a to an integer IDno using atoi. I'm not too sure about this, but I think by using atoi to convert "PT3" to an integer, only the integer "3" will remain in IDno, which is exactly when I want.
edit: the problem appears to be that i am unable to convert "PT3" to an integer using atoi. would appreciate help on getting the number "3" from "PT3" to be stored into IDno.
As per your problem description, looks like you need sscanf(). Something like
sscanf(a, "PT%d", &IDno);
should do the job. Don't forget to do the error check.
Related
I have to write this code, I mean I should read from the file name of students and their mark, and then sort students by the grow of mark. Now I just want to output only mark. I want to display grades using structures. I don't know where the problem is.
text.file
Jon 3
Alina 5
Ron 1
#include <stdio.h>
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include <stdlib.h>
int main()
{
const int N = 3;
int i = 0;
struct student {
char surname[50];
int mark;
};
struct student PI1[N];
char str[50];
const char s[1] = " ";
char* token;
FILE* ptr;
token = strtok(str, s);
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
printf("file can't be opened \n");
}
while (fgets(str, 50, ptr) != NULL){
token = strtok(str, s);
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
PI1[i].mark = atoi(token);
i++;
}
fclose(ptr);
printf("The marks is:\n");
printf("%d %d %d", PI1[0].mark, PI1[1].mark, PI1[2].mark);
return 0;
}
You need to prevent the program from reading from the file pointer if opening the file fails:
ptr = fopen("test.txt", "r");
if (NULL == ptr) {
perror("test.txt");
return 1; // this could be one way
}
The second argument to strok should be a null terminated string. const char s[1] = " "; only has room for one character. No null terminator (\0). Make it:
const char s[] = " "; // or const char s[2] = " "; or const char *s = " ";
Don't iterate out of bounds. You need to check so that you don't try to put data in PI1[N] etc.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
// ^^^^^^^^
Check that strok actually returns a pointer to a new token. If it doesn't, the line you've read doesn't fulfill the requirements.
while (i < N && fgets(str, sizeof str, ptr) != NULL) {
token = strtok(str, s);
if(!token) break; // token check
strcpy(PI1[i].surname, token);
token = strtok(NULL, s);
if (token) // token check
PI1[i].mark = atoi(token);
else
break;
i++;
}
You could also skip the strcpy by reading directly into your struct student since char str[50]; has the same length as surname. str should probably be larger though, but for now:
while (i < N && fgets(PI1[i].surname, sizeof PI1[i].surname, ptr) != NULL) {
token = strtok(PI1[i].surname, s);
if(!token) break;
token = strtok(NULL, s);
if (token)
PI1[i].mark = atoi(token);
else
break;
i++;
}
Only print as many marks as you successfully read
printf("The marks are:\n");
for(int idx = 0; idx < i; ++idx) {
printf("%d ", PI1[idx].mark);
}
putchar('\n');
my struct format is like this
struct {
char student_ID[11];
char full_name [MAX];
char program [MAX];
char year;
char e_mail [MAX*2];
char status;
} student_info;
And this is my function which tries to get one student information
void scanStudents(FILE *file, student_info *student) {
char get_line [500];
fgets(get_line,500,file);
char *ID = strtok(get_line,";");
strcpy(student->student_ID, ID);
char *NAME = strtok(get_line, ";");
strcpy(student->full_name, NAME);
char *PROGRAM = strtok(get_line,";");
strcpy(student->program, PROGRAM);
char *YEAR = strtok(get_line, ";");
strcpy(student->year,YEAR);
char *E_MAIL = strtok(get_line, ";")
strcpy(student->e_mail,E_MAIL);
char *STATUS = strtok(get_line,";");
strcpy(student->status, STATUS);
}
I open file in other function and by calling this function in that my aim is try to store student informations in one array which type is student_ınfo. The txt file contains many student information in type of
31300000010;DURU AY;Computer Engineering;2;duru.ay#tedu.edu.tr;
Here is an example including error fixes that #Retired Ninja and #Gerhardh stated.
The file content is:
31300000010;DURU AY;Computer Engineering;2;duru.ay#tedu.edu.tr;A
Now this one is for storing each field as string. The fixes I made to your code are the following:
student_info declaration and its definition are fixed.
Add MIN_STRING to comply min String length that is 1 character + 1 NULL termination.
Change the year and status fields so that they comply the minimum string space requirements.
Add some NULL checks, perhaps to avoid corrupted student info.
Used only one pointer temp to hold the pointer address which is returned by strtok function.
This sample code is for reference only. So you adapt the idea behind this code to your actual code.
#include <stdio.h>
#include <string.h>
// Minimum string size must be 2 in order to store 1 character + terminating (NULL or '\0') character
#define MIN_STRING 2
#define MAX (50+1) // 1 character space for the NULL terminator.
struct student_info {
char student_ID[12];
char full_name [MAX];
char program [MAX];
char year[MIN_STRING];
char e_mail [MAX];
char status[MIN_STRING];
};
const char *file_name = "students.txt";
int main(void) {
FILE *file_students = fopen(file_name, "r");
if(file_students == NULL) {
printf("The file named %s could not be read\n", file_name);
return 1; // Return with some failure code
}
char get_line[500];
char *temp = NULL;
struct student_info student;
fgets(get_line, 500, file_students);
temp = strtok(get_line,";");
strcpy(student.student_ID, temp);
// After the first invocation of strtok you must pust NULL
temp = strtok(NULL, ";");
// strtok returns NULL if there are not any tokens left
if(temp == NULL) {
puts("Student ID NULL");
return 1;
}
strcpy(student.full_name, temp);
temp = strtok(NULL,";");
if(temp == NULL) {
puts("Name NULL");
return 1;
}
strcpy(student.program, temp);
temp = strtok(NULL, ";");
if(temp == NULL) {
puts("Program NULL");
return 1;
}
strcpy(student.year,temp);
temp = strtok(NULL, ";");
if(temp == NULL) {
puts("Year NULL");
return 1;
}
strcpy(student.e_mail,temp);
temp = strtok(NULL,";");
if(temp == NULL) {
puts("E-mail NULL");
return 1;
}
strcpy(student.status, temp);
puts("Sample student information");
printf(
"ID: %s\nFull name: %s\nProgram: %s\nYear: %s\nE-mail: %s\nStatus: %s\n",
student.student_ID, student.full_name, student.program, student.year,
student.e_mail, student.status
);
// Close the file
fclose(file_students);
return 0;
}
This is the output of the sample code:
Sample student information
ID: 31300000010
Full name: DURU AY
Program: Computer Engineering
Year: 2
E-mail: duru.ay#tedu.edu.tr
Status: A
For example, converting a character of string that contains:
{x1 5.12 x2 7.68 x3}
to double values have been converted to:
0.0000005.1200000.0000007.6800000.000000
How do I convert these double values such that it creates a character array that should be:
{0.000000,5.120000,0.000000,7.680000,0.000000}
I have been looking everywhere to do this conversion and nothing seems to work. If someone may please provide a code to do this conversion. These are my codes:
void exSplit(char newEx[50]){ //newEx[50] contains {x1 5.12
x2 7.68 x3}
char *delim = " ";
char *token = NULL;
char valueArray[50];
char *aux;
int i;
for (token = strtok(newEx, delim); token != NULL; token =
strtok(NULL, delim))
{
char *unconverted;
double value = strtod(token, &unconverted);
printf("%lf\n", value);
}
}
You can use scanf to scan for a float. If a float is found, you print it to the result string. In no float is found, you print the zeros to the result string.
It could look like:
#include <stdio.h>
#include <string.h>
int main(void) {
char newEx[] = "{x1 5.12 x2 7.68 x3}";
char *token;
char result[100] = "{";
char temp[100];
int first = 1;
float f;
for (token = strtok(newEx, " "); token != NULL; token = strtok(NULL, " "))
{
if (first != 1)
{
strcat(result, ",");
}
first =0;
if (sscanf(token, "%f", &f) == 1)
{
sprintf(temp, "%f", f);
}
else
{
sprintf(temp, "0.000000");
}
strcat(result, temp);
}
strcat(result, "}");
printf("%s\n", result);
return 0;
}
Output:
{0.000000,5.120000,0.000000,7.680000,0.000000}
Note: To keep the code example above simple, there is no check for buffer overflow. In real code you should make sure that sprint and strcat wont overflow the destination buffer.
I am having trouble printing this. When I requested the user to insert an int it worked, but when attempting to switch it over to a char input it got screwy and won't print anything.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
const char delim[2] = ",";
char *token;
int j = 0;
char *hh;
FILE *ptr_file;
char buf[1000];
ptr_file = fopen("input.txt", "r");
if (!ptr_file)
return 1;
char *pt[] = { "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na" };
printf("what element do you want(Use atomic number)");
scanf("%s", &hh);
for (j = 0; j <= 3; j++) {
if (hh == pt[j]) {
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, delim);
}
break;
} else {
fgets(buf, 1000, ptr_file);
continue;
}
}
fclose(ptr_file);
return 0;
}
The major problem here is, you are passing scanf() the address of an uninitialized pointer hh. scanf invokes undefined behavior trying to store the word at that address.
You should make hh an array, like char hh[8] = {0}; and use scanf() this way:
scanf("%7s", hh); // to avoid buffer overflow
That said,
if(hh == pt[j]) is not the way to compare strings. You need to use strcmp() to do that, and write if (strcmp(hh, pt[j]) == 0).
you should also check the return value of scanf() to verify if input was correctly converted.
The code
char *hh;
//...
scanf("%s", &hh);
it is UB due to hh uninitialized: it is pointing to garbage.
Furthermore "%s" format specifier wants char * as passed parameter: you are passing char **
should be
char *hh = malloc(MAX_STRING_LEN);
if (hh != NULL)
{
//...
scanf("%s", hh);
}
free(hh);
or simply
char hh[MAX_STRING_LEN] = {0};
//...
scanf("%s", hh);
Into both examples MAX_STRING_LEN expresses the maximum accepted length of string + 1 for null terminator.
Using c you cannot compare strings using logical operator ==, so the code
if(hh == pt[j])
is comparing addresses not the strings.
You can use strcmp to do that.
I want to load information from the file to store in a table but I find that there's an error during loading the information and that the function void charger_Etudiant(Etudiant *E) does not display the information as they are stored in the file, someone to help me please :)
typedef struct Etudiant
{
char nom[64];
char prenom[64];
char CNI[64];
int sante;
int niveau_scolaire;
int Code_confidentiel;
int CNE;
} Etudiant;
the function is:
void charger_Etudiant(Etudiant *E)
{
int i=0;
FILE *fichier = NULL;
fichier = fopen("Info_Etudiant.txt", "r");
if (fichier != NULL)
{
while(i<2&&!feof(fichier))
{
fscanf(fichier,"%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",&E[i].Code_confidentiel,E[i].nom,E[i].prenom,&E[i].CNE,E[i].CNI,&E[i].niveau_scolaire,&E[i].sante);
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",E[i].Code_confidentiel,E[i].nom,E[i].prenom,E[i].CNE,E[i].CNI,E[i].niveau_scolaire,E[i].sante);
i++;
}
fclose(fichier);
}
}
for exemple the information in the file is written in the following form and I want to store them in a table structure :
123 BADR HARI 10043720 SJ26825 1 3
I am not a fan of scanf() or of fscanf(). I prefer to use fgets() and strtok() and sscanf() to extract the fields, although here atoi() is good enough. One advantage of strtok() is that if the field delimitors change, there is only one tweak required.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define STRLENG 63
typedef struct Etudiant {
char nom [STRLENG+1];
char prenom [STRLENG+1];
char CNI [STRLENG+1];
int sante;
int niveau_scolaire;
int Code_confidentiel;
int CNE;
} Etudiant;
int charger_Etudiant(Etudiant *E) {
int i=0;
char buff[512];
char *tok;
char delims[] = "\t\n";
FILE *fichier = NULL;
fichier = fopen("Info_Etudiant.txt", "r");
if (fichier != NULL) {
while(fgets (buff, 512, fichier) != NULL) {
memset(&E[i], 0, sizeof(Etudiant));
if (tok = strtok (buff, delims)) {
E[i].Code_confidentiel = atoi(tok);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].nom, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].prenom, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
E[i].CNE = atoi(tok);
if (tok = strtok (NULL, delims)) {
strncpy (E[i].CNI, tok, STRLENG);
if (tok = strtok (NULL, delims)) {
E[i].niveau_scolaire = atoi(tok);
if (tok = strtok (NULL, delims)) {
E[i].sante = atoi(tok);
}
}
}
}
}
}
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d\n",
E[i].Code_confidentiel, E[i].nom, E[i].prenom,
E[i].CNE, E[i].CNI,E[i].niveau_scolaire,E[i].sante);
i++;
}
}
fclose(fichier);
}
return i;
}
int main() {
return 0;
}
Do not use feof() to detect EOF condition. Check the return value from input functions instead.
Like #Weather Vane suggest using fgets()
.
#define MAXINTLEN (20)
// Use 2x size line buffer
#define MAXLINELEN ((sizeof(Etudiant) + 4*MAXINTLEN) * 2)
char buffer[MAXLINELEN + 2];
while (fgets(buffer, sizeof buffer, fichier) != NULL) {
int cnt = sscanf(buffer,"%d%63s%63s%d%63s%d%d",
&E[i].Code_confidentiel, E[i].nom, E[i].prenom, &E[i].CNE,
E[i].CNI, &E[i].niveau_scolaire, &E[i].sante);
if (cnt != 7) {
break; // scan error
}
printf("%d\t\t%s %s\t\t%d\t\t%s\t\t%d\t\t%d",
E[i].Code_confidentiel, E[i].nom, E[i].prenom, E[i].CNE,
E[i].CNI, E[i].niveau_scolaire, E[i].sante);
i++;
}
When scanning the "\t\t" does not necessarily scan 2 tabs. Any white space in scanf() (except in %[]) scans any number of white spaces. Code could use sscanf(buffer,"%d %63s %63s %d %63s %d %d", ... for clarity, but it does the same thing.
Specifiers "%d" and "%s" consume leading white-space anyways.
Always limit string inputs. Example: %63s