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.
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 have the following code, and I need help getting and storing the last token. Right now the code tokenizes after every space, but when it gets to the end of my text file, it doesn't tokenize the last value. I'm pretty sure I need to have the token before the malloc statements, but when I add it in front, I get a seg fault. Does anybody know the issue? Initialized myStruct.extras = NULL above because of realloc; it is a char **.
token = strtok(fileArrayPTR[p],"X");
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
myStruct.dimensions[1] = strtol(token,&ptr,10);
}else{
myStruct.extras = realloc(myStruct.extras,(extraCounter + 1) * sizeof(char *));
myStruct.extras[extraCounter] = malloc(strlen(token)+1);
strcpy(myStruct.extras[extraCounter],token);
token = strtok(NULL," ");
extraCounter++;
}
}
edit: forgot to put the incremented counter
This is (the second version of) the code from the question:
token = strtok(fileArrayPTR[p],"X");
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
myStruct.dimensions[1] = strtol(token,&ptr,10);
}else{
myStruct.extras = realloc(myStruct.extras,(extraCounter + 1) * sizeof(char *));
myStruct.extras[extraCounter] = malloc(strlen(token)+1);
strcpy(myStruct.extras[extraCounter],token);
token = strtok(NULL," ");
extraCounter++;
}
}
This is not a self-contained program. We can improve it by:
Removing the structure.
Showing corresponding variable declarations.
Converting it into a simple main().
Those changes lead to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int extraCounter = 0;
char **extras = 0;
int tempCounter = 0;
char *ptr = 0;
char data[] = "10X16 something another-thing";
char *token = strtok(data, "X");
int dimension1 = strtol(token, &ptr, 10);
int dimension2 = -1;
while (token!= NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL," ");
dimension2 = strtol(token, &ptr, 10);
tempCounter++;
}
else
{
extras = realloc(extras, (extraCounter + 1) * sizeof(char *));
extras[extraCounter] = malloc(strlen(token)+1);
strcpy(extras[extraCounter], token);
token = strtok(NULL, " ");
extraCounter++;
}
}
printf("Dimensions: %dx%d\n", dimension1, dimension2);
for (int i = 0; i < extraCounter; i++)
printf("%d: [[%s]]\n", i, extras[i]);
return 0;
}
And when run, it produces:
Dimensions: 10x16
0: [[16]]
1: [[something]]
2: [[another-thing]]
Is there a problem with that code? Yes, the code for the dimension2 doesn't reinvoke strtok(), so 16 is processed twice, once as a dimension and once as a string. Probably not what's wanted. Hence:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int extraCounter = 0;
char **extras = 0;
int tempCounter = 0;
char *ptr = 0;
char data[] = "10X16 something another-thing";
char *token = strtok(data, "X");
int dimension1 = strtol(token, &ptr, 10);
int dimension2 = -1;
while (token != NULL)
{
if (tempCounter == 0)
{
token = strtok(NULL, " ");
dimension2 = strtol(token, &ptr, 10);
tempCounter++;
}
else
{
extras = realloc(extras, (extraCounter + 1) * sizeof(char *));
extras[extraCounter] = malloc(strlen(token) + 1);
strcpy(extras[extraCounter++], token);
}
token = strtok(NULL, " ");
}
printf("Dimensions: %dx%d\n", dimension1, dimension2);
for (int i = 0; i < extraCounter; i++)
printf("%d: [[%s]]\n", i, extras[i]);
return 0;
}
Compilation:
gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Werror ss.c -o ss
Output:
Dimensions: 10x16
0: [[something]]
1: [[another-thing]]
Looks better...
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'm writing a basic program that takes a CSV file, prints the first field, and does some numerical evaluation of the other fields.
I'm looking to put all the numerical fields into an array but every time I do this and try to access a random element of the array, it prints the entire thing
My CSV file is:
Exp1,10,12,13
Exp2,15,16,19
and i'm trying to access the second field so it prints
Exp1 12
Exp2 16
but instead I'm getting
Exp1 101213
Exp2 151619
If someone could provide some suggestions. This is my code:
#define DELIM ","
int main(int argc, char *argv[])
{
if(argc == 2) {
FILE *txt_file;
txt_file = fopen(argv[1], "rt");
if(!txt_file) {
printf("File does not exist.\n");
return 1;
}
char tmp[4096];
char data[4096];
char expName[100];
char *tok;
int i;
while(1){
if(!fgets(tmp, sizeof(tmp), txt_file)) break;
//prints the experiment name
tok = strtok(tmp, DELIM);
strncpy(expName, tok, sizeof(expName));
printf("\n%s ", expName);
while(tok != NULL) {
tok = strtok(NULL, DELIM);
//puts data fields into an array
for(i=0; i < sizeof(data); i++) {
if(tok != NULL) {
data[i] = atoi(tok);
}
}
printf("%d", data[1]);
}
}
fclose(txt_file);
return 0;
}
sample to fix
char tmp[4096];
int data[2048];
char expName[100];
char *tok;
int i=0;
while(fgets(tmp, sizeof(tmp), txt_file)){
tok = strtok(tmp, DELIM);
strncpy(expName, tok, sizeof(expName));
printf("\n%s ", expName);
while((tok = strtok(NULL, DELIM))!=NULL){
data[i++] = atoi(tok);
}
printf("%d", data[1]);
i = 0;
}
A modified code snippet:
int data[20]; // change 20 to a reasonable value
...
while (1)
{ if (!fgets(tmp, sizeof(tmp), txt_file))
break;
//prints the experiment name
tok = strtok(tmp, DELIM);
strncpy(expName, tok, sizeof(expName));
printf("\n%s ", expName);
i = 0;
tok = strtok(NULL, DELIM);
while (tok != NULL)
{ //puts data fields into an array
data[i++] = atoi(tok);
if (i == 20)
break;
tok = strtok(NULL, DELIM);
}
if (i > 1)
printf("%d", data[1]);
}
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");
}