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");
}
Related
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 have a char array (buf) that exists out of multiple lines and each line is split up by multiple tabs. I want to separate this. I use the following code for this:
char copy[4096];
char* split_request = strtok(buf, "\r\n");
strcpy(copy, split_request);
while(split_request != NULL) {
if (strchr(copy, '\t') != NULL) {
printf("We have a tab");
//If I uncomment this line I get an assertion error
//char* temp = strtok(copy, '\t');
}
printf(split_request);
split_request = strtok(NULL, "\r\n");
if (split_request != NULL) {
strcpy(copy, split_request);
}
printf("\n");
}
If I uncomment that one line of code, only the first line is processed. In addition, it is printed 5 times, and each time one tabbed column disappears. It feels like despite the strcpy, the original string is still affected...
I was experimenting with an alternative approach to your problem. I have used strtok_r for separating lines and each line is processed using strtok for tabs. The code is given below.
void lineParser(char *singleLine){
const char tab[] = "\t";
char *token = NULL;
if(strchr(singleLine, '\t') != NULL){
token = strtok(singleLine, tab);
while(token != NULL){
printf("%s\n", token);
token = strtok(NULL, tab);
}
}
}
int main()
{
char buf[] = "Stack\tOverFlow\r\nStack\tExchange\r\n";
char *rest = buf;;
char* token = NULL;
const char tab[] = "\t";
const char newline[] = "\r\n";
while ((token = strtok_r(rest, " ", &rest))) {
lineParser(token);
token = strtok_r(rest, newline, &rest);
}
}
bellow is the code:
from some reason the calloc inside the while loop, is failing on the second iteration.
it looks the heap is corupted (not sure) but not clear the root cause.
please also take a look on the comment added there.
appriciate fast response.
#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include<stdio.h>
#include <stdlib.h>
struct User_
{
char* id;
char* firstName;
char* lastName;
int age;
char gender[2];
char* userName;
char* password;
char* description;
char hobbies[2];
}typedef User;
void replaceEnterInString(int lengthString, char* string, int maxChars);
int main()
{
char str1[500] = "012345678;danny;cohen;22;M;danny1993;123;1,2,4,8;Nice person";
char str2[500] = "223325222;or;dan;25;M;ordan10;1234;3,5,6,7;Singer and dancer";
int j = 0;
char *token = NULL, arrangingHobbies;
int lengthStr, tempAge, hobby[4], i;
while(j<2)
{
User* newUser = NULL;
here it pass on first time but fail on second time. but only when adding the code that map the token to the newUser. without the mapping - do manage to calloc the user again and again as much as needed
error code: Critical error detected c0000374 - TEST.exe has triggered a breakpoint.
newUser = (User*)calloc(1, sizeof(User));
if (newUser == NULL)
{
printf("error");
exit(1);
}
//start map string to user
if (j == 0)
{
token = strtok(str1, ";");
printf("%s", str1);
}
else {
token = strtok(str2, ";");
printf("%s", str2);
}
//Input ID
newUser->id = (char*)calloc(10, sizeof(char));
if (newUser->id == NULL)
{
printf("error");
exit(1);
}
strcpy(newUser->id, token);
//Input first name
token = strtok(NULL, ";");
lengthStr = strlen(token);
newUser->firstName = (char*)calloc((lengthStr + 1), sizeof(char));
if (newUser->firstName == NULL)
{
printf("error");
exit(1);
}
strcpy(newUser->firstName, token);
//Input last name
token = strtok(NULL, ",;");
lengthStr = strlen(token);
newUser->lastName = (char*)calloc((lengthStr + 1), sizeof(char));
if (newUser->lastName == NULL)
{
printf("error");
exit(1);
}
strcpy(newUser->lastName, token);
//Input Age
token = strtok(NULL, ",;");
tempAge = atoi(token);
newUser->age = tempAge;
//Input gender
token = strtok(NULL, ",;");
newUser->gender[0] = token[0];
//Input User Name
token = strtok(NULL, ",;");
lengthStr = strlen(token);
newUser->userName = (char*)calloc((lengthStr), sizeof(char));
if (newUser->userName == NULL)
{
printf("error");
exit(1);
}
strcpy(newUser->userName, token);
//Input password
token = strtok(NULL, ",;");
lengthStr = strlen(token);
newUser->password = (char*)calloc((lengthStr), sizeof(char));
if (newUser->password == NULL)
{
printf("error");
exit(1);
}
strcpy(newUser->password, token);
//Input hobbies
newUser->hobbies[0] = 0;
for (i = 0; i < 4; ++i)
{
token = strtok(NULL, ",;");
tempAge = atoi(token);
arrangingHobbies = 1;
arrangingHobbies <<= (tempAge - 1);
newUser->hobbies[0] |= arrangingHobbies;
}
//Input description
token = strtok(NULL, ",;");
newUser->description = (char*)calloc((lengthStr), sizeof(char));
if (newUser->description == NULL)
{
printf("error");
exit(1);
}
replaceEnterInString(strlen(token), token, 300);
strcpy(newUser->description, token);
j++;
}
}
void replaceEnterInString(int lengthString, char* string, int maxChars)
{
if (lengthString < maxChars)
{
//remove the /n
string[lengthString - 1] = '\0';
}
}
Maybe there are other issues as well, yet the following code leads to undefined behaviour for sure:
lengthStr = strlen(token);
newUser->userName = (char*)calloc((lengthStr), sizeof(char));
...
strcpy(newUser->userName, token);
In previous similar statements, you correctly wrote ... = (char*)calloc((lengthStr+1), sizeof(char));.
BTW: In C, you usually don't cast the results of malloc, sizeof(char) is always 1 by definition, and there is no need for setting memory to 0 using calloc if you fill the memory with a subsequent strcpy anyway. So you should write...
lengthStr = strlen(token);
newUser->userName = malloc(lengthStr+1);
...
strcpy(newUser->userName, token);
Look through your code for similar issues, please.
I've used strdup() in the past in the same way that I am using it here. I am passing token2 into strdup which is of type char * with a valid pointer in it, yet when I try to run the line "name = strdup(token2);" my program segfaults and I am quite unsure as to why. If anyone would be able to help me it would be greatly appreciated. I also realize that my code does not return a proper type yet, I am still working on writing all of it.
struct YelpDataBST* create_business_bst(const char* businesses_path, const char* reviews_path){
if(fopen(businesses_path,"r") == NULL || fopen(reviews_path,"r") == NULL)
return NULL;
FILE* fp_bp = fopen(businesses_path, "r");
FILE* fp_rp = fopen(reviews_path, "r");
struct YelpDataBST* yelp = malloc(sizeof(struct YelpDataBST*));
int ID = -1;
int tempID;
long int addressOffset;
long int reviewOffset;
char line[2000];
char line2[2000];
char temp[2000];
char temp2[2000];
char* token;
char* token2;
char* name;
int len;
BusList* busNode = NULL;
BusList* busList = NULL;
BusTree* busTreeNode = NULL;
BusTree* busTree = NULL;
ID = -1;
tempID = 0;
fgets(line,2000,fp_rp);
fgets(line2,2000,fp_bp);
fseek(fp_rp,0, SEEK_SET);
fseek(fp_bp,0,SEEK_SET);
int ct = 0;
while(!feof(fp_rp)){
len = strlen(line);
token = strtok(line, "\t");
//printf("line: %s\n", line);
token2 = strtok(line2, "\t");
tempID = atoi((char*)strdup(token));
if(ct == 0){
tempID = 1;
ct++;
}
if((ID != tempID || (ID < 0)) && tempID != 0){
if(tempID == 1)
tempID = 0;
token2 = strtok(NULL, "\t");
//name = strdup(token2);
reviewOffset = ftell(fp_rp);
if(tempID != 0)
reviewOffset -= len;
addressOffset = ftell(fp_bp);
ID = atoi((char*)strdup(token));
busList = BusNode_insert(busList, addressOffset, reviewOffset); //replace with create node for tree
token2 = strtok(NULL, "\t");
token2 = strtok(NULL, "\t");
token2 = strtok(NULL, "\t");
token2 = strtok(NULL, "\t");
token2 = strtok(NULL, "\t");
token2 = strtok(NULL, "\n");
fgets(line2,2000,fp_bp);
}
token = strtok(NULL, "\t");
token = strtok(NULL, "\t");
token = strtok(NULL, "\t");
token = strtok(NULL, "\t");
token = strtok(NULL, "\n");
fgets(line,2000,fp_rp);
}
//BusList_print(busList);
}
strdup(token) segfaulting is most likely explained by token being NULL. (You don't need to strdup here anyway). Change that piece of code to:
if ( token == NULL )
{
fprintf(stderr, "Invalid data in file.\n");
exit(EXIT_FAILURE); // or some other error handling
}
tempID = atoi(token);
However a greater problem with the surrounding code is that you are trying to use strtok twice at once. It maintains internal state and you can only have one strtok "in progress" at any one time. The second one cancels the first one. You'll have to redesign that section of code.
Also, while(!feof(fp_rp)) is wrong, and your yelp mallocs the wrong number of bytes (although in the code posted you never actually try to store anything in that storage, so it would not cause an error just yet).
I need to make a program that will emulate the terminal of Linux. Since some system calls requires 1,2 or more arguments, I want to make sure that the number of parameters given are correct. I'm using strtok() to separate the call name from the arguments, but I need to know how many tokens strtok() created to compare it.
Here's and example code:
char *comand = (char*) malloc(sizeof(char)*100);
char *token;
char *path1 = (char*) malloc(sizeof(char)*100);
char *path2= (char*) malloc(sizeof(char)*100);
fgets(comand, 100, stdin);
printf( "\nYou entered: %s \n", comand);
token = strtok(comand ," ");
//Check the number of tokens and add a condition in each IF to match
if (strcmp("ls",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("cat",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("cp",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
token = strtok(NULL," ");
strcpy(path2,token);
}
else if (strcmp("mv",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
token = strtok(NULL," ");
strcpy(path2,token);
}
else if (strcmp("find",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("rm",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("mkdir",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("rmdir",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token);
}
else if (strcmp("quit",token) == 0) {
exit(0);
}
else print("Number of parameters do not match);
the only thing strtok() does is look for the next occurance of the delimiter and overwrite that character with a \0 and return the pointer with the offset added. the pointer is kept in a static variable that's why a subsequent call to it with a NULL for the char * will perform it on the last string used from the offset that the last delimiter was found.
this page has a very nice example:
http://en.cppreference.com/w/c/string/byte/strtok
If you only want to count the arguments it would be easier to use strchr(), this function searches for a character and returns a pointer to its location. you could use it like this.
unsigned int i = 0;
char *temp = token;
while ( (temp = strchr(temp, '') != NULL) ) {
++i;
}
this has the added benefit of not modifying your original char array while strtok() does!
I would handle this within the functions you create for each command.
you pass all options to the function and there you parse it. either with strtok() or whatever else you want to use.
This keeps it nice and clean within the sub-routines and you will always know what to expect.
if (strcmp("ls",token) == 0) {
token = strtok(NULL," ");
strcpy(path1,token); // I would maybe change the path variable name to args
ret = lscmd(path1);
if (ret == -1) {
// invalid input detected
}
}
then you would have a ls function
int lsdcmd(char *args) {
// parse args for argumants you are looking for, return -1 if it fails
// do whatever you want to do.
}
You can count the arguments using strtok this way:
Example:
const char* delimiter = ",";
char* tokens[MAX_NUM_OF_ARGS];
unsigned int index = 0;
char* temp = strtok(buff,delimiter);
while (temp!=NULL){
if(index<MAX_NUM_OF_ARGS){
tokens[index]=temp;
}
index++;
temp = strtok(NULL,delimiter);
}
Then later you can iterate through the array of pointers (tokens) and compare them...