Segmentation Fault using Strtok() for 2d array in C - c

I keep getting Segmentation Fault while trying to split a string such as "1,2,3;4,5,6;7,8,9" into a 2d Array why does it keep happening with this code could someone please explain this for me?
int main(void){
char string[100];
char *token;
char *end;
int num;
int row_counter;
int column_counter;
int counter_position;
char *rows[100];
int square_ints[40][40];
row_counter = 0;
column_counter = 0;
string[] = "1,2,3;4,5,6;7,8,9";
token = strtok(string, ";");
rows[row_counter] = token;
row_counter++;
while (token != NULL){
token = strtok(NULL, ";");
rows[row_counter] = token;
row_counter++;
}
counter_position = row_counter;
for (row_counter = 0; row_counter < counter_position; row_counter++) {
token = strtok(rows[row_counter], ",");
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
while (token != NULL) {
token = strtok(NULL, ",");
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
}
}
}
It should be printing: 1 2 3 4 5 6 7 8 9 instead I get 1 2 3 Segmentation Fault

To expand on what MikeCAT mentioned:
As the start of your for loop, you do:
token = strtok(rows[row_counter], ",");
num = strtol(token, &end, 10);
Later you do:
token = strtok(NULL, ",");
num = strtol(token, &end, 10);
The problem is that in both cases, strtok will return NULL, so the value of token is NULL. When you pass token to strtol, it will try to use/dereference this and it will produce a segfault.
So, to fix, after each strtok call, you need to add:
if (token == NULL)
break;
Here's the corrected code. I've added some debug printf, so you can see the issue.
I've used cpp conditionals to demarcate old vs new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Anyway, here it is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
#define dbgprt(_fmt...) \
do { \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { \
} while (0)
#endif
int
main(void)
{
#if 0
char string[100];
#else
char string[] = "1,2,3;4,5,6;7,8,9";
#endif
char *token;
char *end;
int num;
int row_counter;
int column_counter;
int counter_position;
char *rows[100];
int square_ints[40][40];
row_counter = 0;
column_counter = 0;
#if 0
string[] = "1,2,3;4,5,6;7,8,9";
#endif
token = strtok(string, ";");
rows[row_counter] = token;
row_counter++;
while (token != NULL) {
token = strtok(NULL, ";");
rows[row_counter] = token;
row_counter++;
}
counter_position = row_counter;
for (row_counter = 0; row_counter < counter_position; row_counter++) {
dbgprt("DEBUG: rows[%d]='%s'\n",row_counter,rows[row_counter]);
token = strtok(rows[row_counter], ",");
dbgprt("DEBUG: token='%s'\n",token);
#if 1
if (token == NULL)
break;
#endif
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
while (token != NULL) {
token = strtok(NULL, ",");
dbgprt("DEBUG2: token='%s'\n",token);
#if 1
if (token == NULL)
break;
#endif
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
}
}
return 0;
}
Note that while the above code works, it is replicating code before a given loop and inside the loop. If we add an extra pointer variable (e.g. bp), we can simplify the code a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char string[] = "1,2,3;4,5,6;7,8,9";
char *token;
char *end;
int num;
int row_counter;
int column_counter;
int counter_position;
char *bp;
char *rows[100];
int square_ints[40][40];
row_counter = 0;
column_counter = 0;
bp = string;
while (1) {
token = strtok(bp,";");
bp = NULL;
if (token == NULL)
break;
rows[row_counter] = token;
row_counter++;
}
counter_position = row_counter;
for (row_counter = 0; row_counter < counter_position; row_counter++) {
bp = rows[row_counter];
if (bp == NULL)
break;
while (1) {
token = strtok(bp, ",");
bp = NULL;
if (token == NULL)
break;
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
}
}
return 0;
}
There is another similar function strsep that is considered by some to be "strtok done right". Here's a version that uses that function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(void)
{
char string[] = "1,2,3;4,5,6;7,8,9";
char *token;
char *end;
int num;
int row_counter;
int column_counter;
int counter_position;
char *bp;
char *rows[100];
int square_ints[40][40];
row_counter = 0;
column_counter = 0;
bp = string;
while (1) {
token = strsep(&bp,";");
if (token == NULL)
break;
rows[row_counter] = token;
row_counter++;
}
counter_position = row_counter;
for (row_counter = 0; row_counter < counter_position; row_counter++) {
bp = rows[row_counter];
if (bp == NULL)
break;
while (1) {
token = strsep(&bp,",");
if (token == NULL)
break;
num = strtol(token, &end, 10);
square_ints[row_counter][column_counter] = num;
printf("%d\n", square_ints[row_counter][column_counter]);
column_counter++;
}
}
return 0;
}

Related

Unexpected behavior with my token function

I am trying to write a simple Shell in C. Eventually, I will implement forking of processes and piping etc. But, right now, I'm just trying to get all the logic worked out.
I have a partially working shell: When I type exit it exits... however, my token function doesn't seem to be working right.
What am I doing wrong here? I'm not sure why its seg-faulting.
Token prints out once in the while loop and then it seg-faults and crashes.
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#define MAX_BUF_SZ 1024
void checkForPipe(char *string, bool *pipe_bool);
void checkForRedirect(char *string, bool *redirect_bool);
void tokenizeInput(char *string, bool pipe, bool redirect);
int main()
{
char *ptr;
bool is_pipe = 0;
bool is_redirect_out = 0;
bool is_exit = 0;
ptr = (char*)malloc(MAX_BUF_SZ);
while(!is_exit)
{
// Diplay prompt
char cur_dir[MAX_BUF_SZ];
getcwd(cur_dir, MAX_BUF_SZ);
printf("SHELL:%s$ ", cur_dir);
fgets(ptr, MAX_BUF_SZ, stdin);
checkForPipe(ptr, &is_pipe);
checkForRedirect(ptr, &is_redirect_out);
printf("pipe flag = %d\n", is_pipe);
printf("redirect flag = %d\n", is_redirect_out);
if(strcmp(ptr, "exit\n") == 0)
{
is_exit = 1;
}
tokenizeInput(ptr, is_pipe, is_redirect_out);
}
return 0;
}
void checkForPipe(char *string, bool *pipe_bool)
{
char *check_for_pipes;
char *clean_compare;
check_for_pipes = (char*)malloc(MAX_BUF_SZ);
clean_compare = (char*)malloc(MAX_BUF_SZ);
strcpy(check_for_pipes, string);
strcpy(clean_compare, string);
char * token = strtok(check_for_pipes, "|");
if(strcmp(token, clean_compare) == 0)
{
free(clean_compare);
free(check_for_pipes);
}
else
{
*pipe_bool = 1;
free(clean_compare);
free(check_for_pipes);
}
}
void checkForRedirect(char *string, bool *redirect_bool)
{
char *check_for_redirects;
char *clean_compare;
check_for_redirects = (char*)malloc(MAX_BUF_SZ);
clean_compare = (char*)malloc(MAX_BUF_SZ);
strcpy(check_for_redirects, string);
strcpy(clean_compare, string);
char * token = strtok(check_for_redirects, ">");
if(strcmp(token, clean_compare) == 0)
{
free(clean_compare);
free(check_for_redirects);
}
else
{
*redirect_bool = 1;
free(clean_compare);
free(check_for_redirects);
}
}
void tokenizeInput(char *string, bool pipe, bool redirect)
{
char *copy_string;
copy_string = (char*)malloc(MAX_BUF_SZ);
strcpy(copy_string, string);
if(pipe == 0 && redirect == 0)
{
char **args = {NULL};
char *token = strtok(copy_string, " ");
int i = 0;
printf("%s\n", token);
while(token != NULL)
{
args[i] = token;
strtok(NULL, " ");
printf("%s\n", token);
i++;
}
}
/* printf("%s\n%s\n%s\n", args[0], args[1], args[2]); */
}
The problem is on args[i]
I modified your code as follows:
Supposing you have a pre-known number of token which is MAX_BUF_SZ.
You allocate MAX_BUF_SZ pointers of type char*
char **args = malloc(MAX_BUF_SZ * sizeof(char *));
and in the loop, you still have to allocate each pointer char* before using it:
while(token != NULL)
{
args[i] = (char *)malloc(strlen(token)+1);
printf("%s\n", token);
args[i] = token;
token = strtok(NULL, " ");
i++;
}
The whole functions is like this:
void tokenizeInput(char *string, bool pipe, bool redirect)
{
char *copy_string;
copy_string = (char*)malloc(MAX_BUF_SZ);
strcpy(copy_string, string);
// suppose we would have MAX_BUF_SZ tokens
char **args = malloc(MAX_BUF_SZ * sizeof(char *));
if(pipe == 0 && redirect == 0)
{
char *token = strtok(copy_string, " ");
int i = 0;
//printf("token %s\n", token);
while(token != NULL)
{
args[i] = (char *)malloc(strlen(token)+1);
printf("%s\n", token);
args[i] = token;
token = strtok(NULL, " ");
i++;
}
}
/* printf("%s\n%s\n%s\n", args[0], args[1], args[2]); */
}
Here is my example running :
SHELL:D:\Users\T0180694\Documents\Mes Outils Personnels\PAN\PAN_folder$ test is essai of you and me
pipe flag = 0
redirect flag = 0
test
is
essai
of
you
and
me

Converting struct in main() into function version [duplicate]

This question already has answers here:
How to access a local variable from a different function using pointers?
(10 answers)
Why can a function return an array setup by malloc but not one setup by "int cat[3] = {0,0,0};"
(7 answers)
Dynamically allocate memory for Array of Structs
(5 answers)
Closed 5 years ago.
I'm new to C programming. I just figured out how to read csv files into C by struct, but struggling to convert the script into a function, then call this function in int main(). I'll need to read loads of csv files so a function will be very helpful.
Here is my code which runs successfully (non-function version):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXROWS 2
struct cudaScenarioStruct{
char *type;
int trial;
int yPC;
int yPE;
int n;
};
struct cudaScenarioStruct cudaScenario[MAXROWS];
int main(){
int rowIndex = 0;
char line[128];
char* token = NULL;
FILE* fp = fopen("C:/Users/ms710557/Desktop/cudaScenario1(2).csv","r");
if (fp != NULL){
while (fgets( line, sizeof(line), fp) != NULL && rowIndex < MAXROWS){
cudaScenario[rowIndex].type = malloc(2);
token = strtok(line, ",");
strcpy(cudaScenario[rowIndex].type, token);
token = strtok(NULL, ",");
cudaScenario[rowIndex].trial = atoi(token);
token = strtok(NULL, ",");
cudaScenario[rowIndex].yPC = atoi(token);
token = strtok(NULL, ",");
cudaScenario[rowIndex].yPE = atoi(token);
token = strtok(NULL, ",");
cudaScenario[rowIndex].n = atoi(token);
rowIndex++;
}
fclose(fp);
}
for (int i = 0; i < MAXROWS; ++i){
printf("%s, %i, %i, %i, %i \n", cudaScenario[i].type, cudaScenario[i].trial, cudaScenario[i].yPC, cudaScenario[i].yPE, cudaScenario[i].n);
}
return 0;
}
The results look like this:
NI, 1, 61, 55, 80
NI, 2, 54, 59, 80
However when I convert it into a function and include the function in int main(), it's just not working... I've been googling for hours and couldn't find out why. This is my attempt:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXROWS 2
struct cudaScenarioStruct{
char *type;
int trial;
int yPC;
int yPE;
int n;
};
struct cudaScenarioStruct *readCudaScenarioData(){
struct cudaScenarioStruct csvData[MAXROWS];
int rowIndex = 0;
char line[128];
char* token = NULL;
FILE* fp = fopen("C:/Users/ms710557/Desktop/cudaScenario1(2).csv","r");
if (fp != NULL){
while (fgets( line, sizeof(line), fp) != NULL && rowIndex < MAXROWS){
csvData[rowIndex].type = malloc(2);
token = strtok(line, ",");
strcpy(csvData[rowIndex].type, token);
token = strtok(NULL, ",");
csvData[rowIndex].trial = atoi(token);
token = strtok(NULL, ",");
csvData[rowIndex].yPC = atoi(token);
token = strtok(NULL, ",");
csvData[rowIndex].yPE = atoi(token);
token = strtok(NULL, ",");
csvData[rowIndex].n = atoi(token);
rowIndex++;
}
fclose(fp);
}
return csvData;
}
int main()
{
struct cudaScenarioStruct *cudaScenario;
cudaScenario = readCudaScenarioData();
for (int i = 0; i < MAXROWS; ++i){
printf("%s, %i, %i, %i, %i \n", cudaScenario[i].type,
cudaScenario[i].trial, cudaScenario[i].yPC, cudaScenario[i].yPE,
cudaScenario[i].n);
}
return 0;
}
Any help will be highly appreciated!

Why am I getting "undefined reference to" error?

The code below throws an error "undefined reference to 'poredi'".
Everything is defined in this single c file (aside from the c libs in include).
'poredi' is just a function, of which I define a prototype right below the typedef and then I impelement it lower in the file.
Looking at some of the similar questions I can say that it is compiled on Windows 10 using the MinGW C compiler through the CodeBlocks IDE without any additional arguments for compiling.
I am a total C noob so any help is appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char ime[20];
char prezime[20];
char registracija[10];
int dRod;
int mRod;
int gRod;
char datumIzdavanja[10];
} vozac;
void poredi(vozac *vozaci, int linije);
int nlines(char *datoteka);
void napuni(FILE *ulaz, vozac *vozaci, int lines);
int main(){
int lines = nlines("Registar.in");
FILE *ulaz = fopen("Registar.in", "r");
int i;
FILE *izlaz = fopen("Najmladji.out", "w");
vozac *vozaci = calloc(lines,sizeof(vozac));
napuni(ulaz,vozaci,lines);
fclose(ulaz);
poredi(vozaci,lines);
for (i = 0; i < 5; i++){
printf("\n%s %s (%d.%d.%d)", vozaci[i].ime, vozaci[i].prezime, vozaci[i].dRod, vozaci[i].mRod, vozaci[i].gRod);
}
fclose(izlaz);
return 0;
}
int nlines(char *datoteka){
FILE *ulaz = fopen("Registar.in", "r");
int brojac = 0;
while (!feof(ulaz)){
char ch = fgetc(ulaz);
if (ch == '\n') brojac++;
}
fclose(ulaz);
return brojac;
}
void napuni(FILE *ulaz, vozac *vozaci, int lines){
int i;
char *linija = calloc(70, sizeof(char));
char *token;
char *token2;
char *znak;
char *znak2;
for (i= 0; i < lines; i++){
fgets(linija,70,ulaz);
token = strtok(linija," ");
strcpy(vozaci[i].prezime, token);
znak = strchr(vozaci[i].prezime,',');
*znak = 0;
token = strtok(NULL," ");
strcpy(vozaci[i].ime, token);
znak2 = strchr(vozaci[i].ime, ';');
*znak2 = 0;
token = strtok(NULL, " ");
strcpy(vozaci[i].registracija, token);
token = strtok(NULL, " ");
token2 = strtok(token, ".");
vozaci[i].dRod = atoi(token2);
token2 = strtok(NULL, ".");
vozaci[i].mRod = atoi(token2);
token2 = strtok(NULL, ".");
vozaci[i].gRod = atoi(token2);
token = strtok(NULL, " ");
strcpy(vozaci[i].datumIzdavanja, token);
}
void poredi(vozac *vozaci, int linije){
int sortirano = 1;
vozac buffer;
while (sortirano){
sortirano = 0;
for (i = 0; i < linije; i++){
if (vozaci[i].gRod > vozaci[i+1].gRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
else if (vozaci[i].gRod == vozaci[i + 1].gRod){
if (vozaci[i].mRod > vozaci[i + 1].mRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
else if (vozaci[i].mRod == vozaci[i + 1].mRod){
if (vozaci[i].dRod > vozaci[i + 1].dRod){
buffer = vozaci[i];
vozaci[i] = vozaci[i+1];
vozaci[i + 1] = buffer;
sortirano = 1;
}
}
}
}
}
}
}
You have poredi() defined inside napuni(). Nested functions is not valid in ISO C but gcc allows it as an extension. I doubt you actually intended to use nested functions but misplaced of braces. Basically remove one brace } from the end of your source file add it above the definition of poredi().
A better indentation would have help avoid such surprises.

Segmentation Fault with strlen

I am getting a segmentation fault error. When I comment out "wordlength = strlen(token);" it runs fine. I don't know why it the seg fault happens when I assign a strlen(token) just fine to an int a few lines before this one. I would appreciate any help possible.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define char_max 60
int main(int argc, char *argv[])
{
FILE *fp = fopen(argv[2],"r");
char **wordlist;
int row = 1;
int i;
char temp[100];
char *token;
int wordlength;
int lengthcounter;
wordlist = (char**)malloc(row*sizeof(char*));
for(i = 0; i < row; i++)
{
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
}
while(fgets(temp, sizeof(temp), fp) != NULL)
{
lengthcounter = 0;
wordlength = 0;
token = strtok(temp, " ");
strcat(wordlist[row-1], token);
printf("%s\n", wordlist[row-1]);
lengthcounter = strlen(token);
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
printf("The lengthcounter is %d\n", lengthcounter);
}
free(wordlist);
fclose(fp);
return 0;
}
while(token != NULL)
{
token = strtok(NULL, " ");
wordlength = strlen(token);
/*lengthcounter += wordlength;*/
}
What happens in the last iteration of the loop when token is NULL? You pass it to strlen anyway.
Also, this is almost certainly wrong:
wordlist[i] = (char*)malloc(char_max*sizeof(char*));
You're allocating space for pointers, not characters. So why sizeof(char*)? Also, don't cast the return value of malloc. This is C, not C++.

Strtok using dynamic memory

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

Resources