C - segfault when trying to use strdup - c

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).

Related

What causes a Sigtrap crash with realloc in C?

in my C program i'm trying to create an array of structs. For memory allocation im trying to make it dynamic, growing as long as it needs to, unfortunately, everytime it crashes on the realloc.
void readsaveusers(char* filename, User *users) {
FILE *file;
file = fopen(filename, "r");
if (file == NULL) printf("Error reading file\n");
char line[200];
users = malloc(sizeof(struct user *));
for (int i = 0; !feof(file); i++) {
fgets(line, 200, file);
users = realloc(users,sizeof(struct user *) * (i + 1));
char *tok = strtok(line, ";");
strcpy(users[i].username, tok);
tok = strtok(NULL, ";");
strcpy(users[i].name, tok);
tok = strtok(NULL, ";");
users[i].gender = tok[0];
tok = strtok(NULL, "/");
users[i].birth_date.day = atoi(tok);
tok = strtok(NULL, "/");
users[i].birth_date.month = atoi(tok);
tok = strtok(NULL, ";");
users[i].birth_date.year = atoi(tok);
tok = strtok(NULL, "/");
users[i].account_creation.day = atoi(tok);
tok = strtok(NULL, "/");
users[i].account_creation.month = atoi(tok);
tok = strtok(NULL, ";");
users[i].account_creation.year = atoi(tok);
tok = strtok(NULL, ";");
strcpy(users[i].pay_method, tok);
tok = strtok(NULL, ";");
strcpy(users[i].account_status, tok);
}
printf("Saved file\n");
fclose(file);
}
This:
users = realloc(users,sizeof(struct user *) * (i + 1));
^
|
|
doh!
allocates memory for i + 1 pointers to struct user. Assuming the structure itself is larger than a pointer to it (a reasonable assumption), you will overwrite the allocated memory and bomb.
You meant:
void * const np = realloc(users, (i + 1) * sizeof *users);
if (np != NULL)
{
users = np;
}
else
{
fprintf(stderr, "Memory allocation failure, aborting\n");
exit(1);
}
Note use of "new pointer" (np) variable to check if the allocation succeeds. This could be simplified since the original value is not actually needed when doing an exit() to handle the error, but I left it as illustration.

calloc issue on second time - on C

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.

Breaking down a string and putting it into array using strtok()

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]);
}

C struct string error

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

Adding Tokens to an Array C

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");
}

Resources