What I am trying to do is to read input from file which is in the format of Data1;Data2;Data3;Data4;Data5 I want to tokenize this string, and store each of these separate pieces of information in a structure such as;
struct example {
char data1[10];
char data2[10];
char data3[10];
char data4[10];
char data5[10];
};
Here's what I have for my input function so far:
void userInput() { // I will need to change return type
FILE *file;
char buffer[BUFFER_SIZE];
struct example data[5];
file = fopen(DATA, "r");
if(file == NULL) {
printf("Error opening data file.\n");
}
while(fgets(buffer, BUFFER_SIZE, file) != null) {
//tokenize strings, and add to struct here
}
}
I realize that in my while function I will need something like:
....
char *token = NULL;
token = strtok(string, ";");
while(token != NULL) {
// add to struct here
token = strtok(NULL, ";");
}
Could someone explain how I would loop through my struct to add this? Or if I'm even going about this the proper way?
You have two things you want to iterate over. I assume each line of input corresponds to a different struct example. Then, you want to iterate over each field in your structure. You need a counter to iterate over your data array, and then you need a mechanism to iterate over the fields. I would use a temporary array to accomplish that:
int i = 0;
while(fgets(buffer, BUFFER_SIZE, file) != null && i < 5) {
char *fields[] = {
data[i].data1, data[i].data2, data[i].data3,
data[i].data4, data[i].data5
};
size_t lengths[] = {
sizeof(data[i].data1), sizeof(data[i].data2), sizeof(data[i].data3),
sizeof(data[i].data4), sizeof(data[i].data5)
};
char *token = NULL;
int j = 0;
token = strtok(string, ";");
while(token != NULL && j < 5) {
snprintf(fields[j], lengths[j], "%s", token);
token = strtok(NULL, ";");
++j;
}
++i;
}
If you want to use a struct, you need some sort of counter to differentiate between your structure elements. Something like:
int x = 0;
while(token != NULL) {
token = strtok(NULL, ";");
// add to struct here
if (x == 0){
data1 = token;
}else if (x == 1){
data2 = token;
}else if (...)
// ... keep going
x++;
}
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');
I am trying to create a program that takes in a number of processes (name, start time, remaining time) from a file, then uses a round robin algorithm to handle the queue.
The issue is, when I try to tokenize each line of the file by using strtok() and fgets(), the name of the process is always wrong.
For example, if the first line is P1 0 3 the output is like this:
void RoundRobin(char *filename) {
Queue *q = initQueue();
char string[MAX_SIZE];
FILE *file;
Process process[20];
char *token;
file = fopen(filename, "r");
if (!file) {
printf("File Cannot Be Opened");
}
fgets(string, 150, file);
token = strtok(string, "=");
token = strtok(NULL, "+");
int time_quantum = atoi(token);
int process_count = 0;
while (fgets(string, 150, file)) {
char *token1;
token1 = strtok(string, " ");
process[process_count].name = token1;
token1 = strtok(NULL, " ");
process[process_count].starting_time = atoi(token1);
token1 = strtok(NULL, " ");
process[process_count++].remaining_time = atoi(token1);
token1 = strtok(NULL, " ");
}
for (int i = 0; i < process_count; i++) {
printf("%s %d %d\n", process[i].name, process[i].starting_time, process[i].remaining_time);
}
fclose(file);
}
You are reusing a single char[] for all of your token parsing. fgets() will overwrite the contents of that char[] each time, and strtok() will return pointers to memory inside of that char[]. Thus, each time you read a new line from the file, the previous pointers you already stored in the process[] array are still pointing at the same memory, but the contents of that memory have been altered.
You need to instead allocate a separate char[] string for each name that you want to save in the process[] array. You can use strdup() for that, eg:
while (fgets(string, 150, file)){
char* token1 token1 = strtok(string, " ");
process[process_count].name = strdup(token1); // <-- HERE
...
}
// use process[] as needed...
for(int i = 0; i < process_count; i++){
free(process[i].name);
}
The problem is strtok() returns a pointer into the line that it parses. Hence all entries in the process array point to the same string array that is modified by the call to fgets().
You must duplicate the string you store in the process description structure:
void RoundRobin(const char *filename) {
char string[MAX_SIZE];
Process process[20];
Queue *q = initQueue();
char *token;
FILE *file;
file = fopen(filename, "r");
if (!file) {
printf("Cannot open file %s\n", filename);
return;
}
int time_quantum = 0;
int process_count = 0;
if (fgets(string, sizeof string, file)
&& (token = strtok(string, "=")) != NULL
&& (token = strtok(NULL, "+")) != NULL) {
time_quantum = atoi(token);
}
while (fgets(string, sizeof string, file)) {
char *token1;
if ((token1 = strtok(string, " ")) == NULL)
contine;
process[process_count].name = strdup(token1);
if ((token1 = strtok(string, " ")) == NULL)
contine;
process[process_count].starting_time = atoi(token1);
if ((token1 = strtok(string, " ")) == NULL)
contine;
process[process_count].remaining_time = atoi(token1);
process_count++;
}
for (int i = 0; i < process_count; i++) {
printf("%s %d %d\n", process[i].name, process[i].starting_time, process[i].remaining_time);
}
for (int i = 0; i < process_count; i++) {
free(process[i].name);
}
fclose(file);
}
I am learning about how to use token to analyze file and put it in struct array. My code compiles fine, but it crashes while running it. Can someone please help?
Here is my code:
struct state_info {
char code[3];
unsigned long num_records;
unsigned long total_income;
unsigned long total_vehicles;
unsigned long total_population;
unsigned long total_rent;
unsigned long total_renter;
};
int main(int argc, char *argv[]) {
const int num_states = 100;
struct state_info *states[num_states];
FILE *file = fopen(argv[i], "r");
analyze_file(file, states, num_states);
}
void analyze_file(FILE *file, struct state_info *states[], int num_states) {
const int line_sz = 100;
char line[line_sz];
while (fgets(line, line_sz, file) != NULL) {
char* token = strtok(line, " \n");
while(token != NULL) {
//allocate memory
int size = atoi(token);
if(states[size] == NULL) {
states[size] = malloc(sizeof(struct state_info));
states[size]->num_records = 0;
states[size]->total_income = 0;
states[size]->total_vehicles = 0;
states[size]->total_population = 0;
states[size]->total_rent = 0;
states[size]->total_renter = 0;
}
//add value to the states
token = strtok(NULL, " \n");
strcpy(states[size]->code, token);
token = strtok(NULL, " \n");
states[size]->total_population += atoi(token);
token = strtok(NULL, " \n");
states[size]->total_income += atoi(token);
token = strtok(NULL, " \n");
states[size]->total_vehicles += atoi(token);
token = strtok(NULL, " \n");
//calculate total rent and total renter
if(atoi(token) != 0) {
states[size]->total_rent += atoi(token);
states[size]->total_renter++;
}
}
states[size]->num_records++;
token = strtok(NULL, " \n");
}
}
I think there should be something wrong with my pointer but I am not sure about it.
Statement struct state_info *states[num_states] does not initialize the pointer array with NULL-values, such that it may contain "garbage" (i.e. pointers != NULL pointing to something not being a valid object).
Hence, a comparison like if(states[size] == NULL) will probably never evaluate to true and will consequently never allocate a proper object. Subsequent access to states[size] will lead to undefined behaviour (actually the access states[size]==... already is undefined behaviour, yet I bet that the "crash" is due to the subsequent access)
Maybe there are other issues as well; yet I think that this is the most obvious thing in your code.
Fix it by initialising states, e.g. struct state_info *states[num_states] = { NULL }
Here are some chunks of my code to give you a view of my problem
typedef struct {
int count;
char *item;
int price;
char *buyer;
date *date;
}transaction;
transaction *open(FILE *src, char* path) {
char buffer[100], *token;
int count = 0;
transaction *tlist = (transaction*)malloc(sizeof(transaction));
tlist = alloc(tlist, count);
src = fopen(path, "r");
if (src != NULL) {
printf("\nSoubor nacten.\n");
}
else {
printf("\nChyba cteni souboru.\n");
return NULL;
}
while (fgets(buffer, sizeof(buffer), src)) {
tlist = alloc(tlist, count+1);
token = strtok(buffer, "\t"); //zahodit jméno obchodníka
tlist[count].count = strtok(NULL, "x");
tlist[count].item = strtok(NULL, "\t");
tlist[count].item++;
tlist[count].item[strlen(tlist[count].item)] = '\0';
tlist[count].price = atoi(strtok(NULL, "\t "));
token = strtok(NULL, "\t"); //zahodit md
tlist[count].buyer = strtok(NULL, "\t");
tlist[count].date = date_autopsy(strtok(NULL, "\t"));
count++;
}
fclose(src);
return tlist;
}
transaction *alloc(transaction *tlist, int count) {
if (count == 0) {
tlist[0].item = (char*)malloc(20 * sizeof(char));
tlist[0].buyer = (char*)malloc(20 * sizeof(char));
}
else {
tlist = (transaction*)realloc(tlist, count * sizeof(transaction));
tlist[count - 1].item = (char*)malloc(20 * sizeof(char));
tlist[count - 1].buyer = (char*)malloc(20 * sizeof(char));
}
return tlist;
}
First in main(), I create the list
transaction *list = (transaction*)malloc(sizeof(transaction));
Then with the right command, I call my opening function that loads a file, then it tokens a line from that file into pieces that then puts into the structure. It all works fine.. When I want to print(for testing) tlist[count].item inside the opening function, it prints the right thing. But when I try it outside(in main()), it prints garbage. It somehow works for the date and price parts of sturcture.. I assume the "buyer" string will be broken as well. Thanks in advance
Since you are overwriting the allocated memory with the local buffer for the item , bueyr fields so it is not reflected in the caller function. Modify the code as below
tlist[count].count = strtok(NULL, "x") -> strcpy(tlist[count].count, strtok(NULL, "x"))
tlist[count].buyer = strtok(NULL, "\t") -> strcpy(tlist[count].buyer , strtok(NULL, "\t"))
and also check the tlist[count].date , You should allocate the memory for the date and also use memcpy to copy the contents.
Since strtok returns the NULL termintated string what is the use of the following lines ?
tlist[count].item++;
tlist[count].item[strlen(tlist[count].item)] = '\0';
strtok holds an internal static buffer which is filled and returned after every call.
somerthing like this:
char *strtok(...)
{
static char buf[XX];
// get next token
return buf;
}
You are effectively assigning and therefore overwriting the data the pointer points to after every call.
A better use would be to allocate memory for the char * fields and use strcpy for the data returned from strtok
So I'm trying to add tokens to an array the if statement keeps verifying that the array, tokenHolder, is empty. My second while loop is where I try to input tokens into the array. However no tokens are inputted into the array and I don't understand why.
char* token;
int* bufflength = 0;
char* buffer = NULL;
char input[25000];
char *tokenHolder[2500];
int pos = 0;
while(1){
printf("repl> ");
getline(&buffer, &bufflength, stdin);
token = strtok(buffer, "");
//code to input tokens into array
while(token != NULL){
pos++;
token = strtok(NULL, "");
tokenHolder[pos] = token;
}
if(tokenHolder[0] == NULL){
printf("It's NULL");
}
}
You increment pos to 1 before you save any token, so nothing is ever assigned to tokenHolder[0].
Either use (note the use of blank rather than an empty string as the delimiter):
tokenHolder[0] = token = strtok(buffer, " ");
(or an equivalent) or do something like:
char *data = buffer;
while ((tokenHolder[pos++] = strtok(data, " ")) != NULL)
data = NULL;
char *tokenHolder[2500] = { NULL };
...
while(token != NULL){
tokenHolder[pos++] = token;
token = strtok(NULL, "");
}
if(tokenHolder[0] == NULL){//or if(pos == 0){
printf("It's NULL");
}