strtok in C crashes with char pointer - c

I have a char array in C with numbers separated by comma, and need to convert it to an int array. However when I try to use strtok, it crashes with EXC_BAD_ACCESS.
Can you help me please?
The method
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARRAY_LEN (0x100)
#define OUTPUT_LEN (0x400)
unsigned int StaticAnalyze_load( char* data, char delimiter, int* array, unsigned int length ){
char *token;
int i=0;
// CRASHES HERE (BAD ACCESS)
token = strtok(data, &delimiter);
while( token != NULL ) {
array[i] = atoi(token);
token = strtok(NULL, &delimiter);
i++;
}
for(i=0;i<3;i++) {
printf("%d\n", array[i]);
}
return length;
}
Main
int main(int argc, const char * argv[]) {
char *data = "13,654,24,48,1,79,14456,-13,654,13,46,465,0,65,16,54,1,67,4,6,74,165,"
"4,-654,616,51,654,1,654,654,-61,654647,67,13,45,1,54,2,15,15,47,1,54";
int array[ARRAY_LEN]; // array, I need to fill-in with integers from the string above
unsigned int loaded = StaticAnalyze_load(data, ',', array, ARRAY_LEN);
return 0;
}

data in main is a pointer to a literal string that strtok cannot modify.
strchr could be used to identify the tokens.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARRAY_LEN (0x100)
#define OUTPUT_LEN (0x400)
unsigned int StaticAnalyze_load( char* data, char delimiter, int* array, unsigned int length ){
char *token = data;
int i=0;
while( i < ARRAY_LEN && token != NULL ) {
array[i] = atoi(token);
token = strchr(token, delimiter);
if ( token) {
++token;
}
i++;
}
for(i=0;i<3;i++) {
printf("%d\n", array[i]);
}
return length;
}
int main(int argc, const char * argv[]) {
char *data = "13,654,24,48,1,79,14456,-13,654,13,46,465,0,65,16,54,1,67,4,6,74,165,"
"4,-654,616,51,654,1,654,654,-61,654647,67,13,45,1,54,2,15,15,47,1,54";
int array[ARRAY_LEN]; // array, I need to fill-in with integers from the string above
unsigned int loaded = StaticAnalyze_load(data, ',', array, ARRAY_LEN);
return 0;
}

Related

How to split with multiple delimiters in C

I have this line of text:
32+-#3#2-#3#3
I need to separate numbers from each other. So basically the result would be like this:
3
2+-
3
2-
3
3
This is my code but it's not working properly because I have numbers with two digits:
#include <stdio.h>
#include <string.h>
int main(void) {
char string[50] = "32-#3#2-#3#3";
// Extract the first token
char *token = strtok(string, "#");
// loop through the string to extract all other tokens
while (token != NULL) {
printf(" %s\n", token); //printing each token
token = strtok(NULL, "#");
}
return 0;
}
You can't do it with strtok (alone), because there is no delimiter between the numbers you want to split. It's easier without strtok, just print what you want printed and add a separator unless a character which belongs to the token follows:
#include <stdio.h>
int main()
{
char string[] = "32+-#3#2-#3#3";
for (char *token = string; *token; ++token)
if ('0'<=*token && *token<='9' || *token=='+' || *token=='-')
{
putchar(*token);
if (token[1]!='+' && token[1]!='-') putchar('\n');
}
}
If you consider this too easy, you can use a regular expression to match the tokens:
#include <stdio.h>
#include <regex.h>
int main()
{
char *string = "32+-#3#2-#3#3";
regex_t reg;
regcomp(&reg, "[0-9][+-]*", 0);
regmatch_t match = {0};
while (regexec(&reg, string+=match.rm_eo, 1, &match, 0) == 0)
printf("%.*s\n", (int)(match.rm_eo-match.rm_so), string+match.rm_so);
}
There is a simple way to achieve this, but in C is a bit more complicated since we don't have vector as in C++ but I can suggest a pure C implementation which can be improved:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void split_ss(const char* src,const char* pattern, char** outvec, size_t* outsize)
{
const size_t pat_len = strlen(pattern);
char* begin = (char*) src;
const char* next = begin;
if ((begin = strstr((const char*)begin, pattern)) != 0x00) {
unsigned int size = begin - next;
*outvec = malloc(sizeof(char) * size);
memcpy(*outvec , next, size);
outvec++;
(*outsize)+=1;
split_ss(begin+pat_len, pattern, outvec, outsize);
} else {
unsigned int size = &src[strlen(src)-1] - next + 1;
*outvec = malloc(sizeof(char) * size);
memcpy(*outvec, next, size);
(*outsize) += 1;
}
}
int main()
{
char* outdata[64] = {0};
size_t size, i=0;
split_ss("32+-#3#2-#3#3", "#", outdata, &size);
for(i=0; i < size; i++) {
printf("[%s]\r\n", outdata[i]);
}
// make sure to free it
return 0;
}
strstr is used to split by string rather than a character. Also output is a poorman 2D array with out size to iterate it and don't forget to free it.
strtok() is not the right tool for you purpose... As a matter of fact strtok() is rarely the right tool for any purpose because of its tricky semantics and side effects.
A simple loop will do:
#include <stdio.h>
int main(void) {
char string[50] = "32+-#3#2-#3#3";
for (char *p = string; *p; p++) {
if (*p == '#')
continue;
putchar(*p);
while (p[1] == '+' || p[1] == '-')
putchar(*++p);
putchar('\n');
}
return 0;
}

C: Strange behaviour with strtok()

I'm doing an exercice where I need to split a string into an array of strings. The number of delimiters is checked before (the code snippet posted is a stripped down version however it doesn't work too), then the string is transformed into lowercase and it gets split into 4 parts separated by the delimiter "-". Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define MAX_USERNAME_LENGHT 256
#define NUMBER_OF_ELEMENTS 4
void StringToArrayOfStrings(char *string, char **string_array, char *delimiter);
void LowerString(char * string, int string_lenght);
int main() {
char string[MAX_USERNAME_LENGHT] = "Joseph-Lucy-Mike-Nick"; //Test string
char *string_array[NUMBER_OF_ELEMENTS]; //We need four elements
char delimiter[] = "-";
int counter = 0;
//LowerString(string, strlen(string));
//printf("%s", string);
StringToArrayOfStrings(string, string_array, delimiter);
//Print each element of the string array
for (counter = 0; counter < NUMBER_OF_ELEMENTS; counter++) {
printf("\n%s\n", string_array[counter]);
}
return 0;
}
void LowerString(char * string, int string_lenght) {
unsigned short int counter;
for (counter = 0; counter < string_lenght; counter++) {
string[counter] = tolower(string[counter]);
}
}
void StringToArrayOfStrings(char *string, char **string_array, char *delimiter) {
unsigned short int counter;
char *token;
token = strtok(string, delimiter);
while(token != NULL) {
string_array[counter++] = token;
token = strtok(NULL, delimiter);
}
}
I've been scratching my head for the past 2 hours and I wasn't able to fix it. This programs works only if the string is not printed or/and transformed in lowercase. The program crashes when entering the loop in StringToArrayOfStrings. Where's the problem?
Thanks.

Finding last character

I'm new to C and trying to create a function that check a string and returns the last character.
I get the function to print the correct letter, but I cant figure out how to return it :/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char last_chr(char *c);
int main (int argc, const char * argv[]) {
char *text[15];
strcpy(text, "*find:last;char#");
last_chr(text); //debugging
//printf("last char: %c", last_chr(text)); //not working
return 0;
}
char last_chr(char *c) {
char *endchr;
char result;
int pos = strlen(c)-1;
endchr = c[pos];
//sprintf(result,"%s",endchr); //"EXEC_BAD_ACCESS"
putchar(endchr); //prints #
//putc(endchr, result); //"EXEC_BAD_ACCESS"
//printf(endchr); //"EXEC_BAD_ACCESS"
return result;
}
You don't assign result. You probably mean
result = c[pos];
instead of endchr = c[pos];
endchr is a character-pointer instead of a character.
#include <stdio.h>
#include <string.h>
char last_chr(char *c);
int main (int argc, const char * argv[]) {
char text[32];//char *text[15]
strcpy(text, "*find:last;char#");//length is 17
printf("last char: %c", last_chr(text));//#
return 0;
}
char last_chr(char *c) {
if(c == NULL || *c == '\0') return 0;
return c[strlen(c)-1];
}

Tokenized string of char to ints using atoi

I am trying to take user input: (1 345 44 23) and make it into a tokenized char string then into ints. Surprisingly I could not find much help for what I would think would be a common task.
Any ideas how to convert the char string into an in string using tokens?
My program crashes when it gets to the conversion (after the tokenization [I realize this is not a word]).
Thanks!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void strInput (char str[], int maxChars);
void custatoi(char * tokenArray[], int * data, int numOfTok);
int main(int argc, char *argv[])
{
char str[StrSZE];
char* tokenArray;
int maxChars=StrSZE-1, cont=1, numOfToken=0, i=0;
int* data;
strInput(str, maxChars);
tokenArray = strtok(str, " \t");
while (tokenArray)
{
printf("token: %s\n", tokenArray);
tokenArray = strtok(NULL, " \t");
numOfToken++;
}
data = (int *) malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
system("PAUSE");
return 0;
}
void strInput (char str[], int maxChars)
{
char garbage;
int k=0;
str[0]='\0';
printf("Please type a string of whole numbers (intigers).\n\n");
while ((k<80) && ((str[k] = getchar()) != '\n'))
k++;
/* Clears the keyboard buffer. */
if (k==80)
while((garbage = getchar()) != '\n')
;
/* Place null at the end of the line read in from user */
str[k]='\0';
printf("str after input is: %s\n\n", str);
}
void custatoi(char * tokenArray[], int * data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
I corrected the errors in yours code: There was some mistakes in main(), tokenArray data type was not correct.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void strInput (char str[], int maxChars);
void custatoi(char* tokenArray[], int * data, int numOfTok);
int main(int argc, char *argv[])
{
char str[StrSZE];
int maxChars=StrSZE-1, cont=1, numOfToken=0, i=0;
int* data;
char* tokenArray[50]; // Declared correctly
strInput(str, maxChars);
tokenArray[i] = strtok(str, " \t"); // Also made a change here!
while (tokenArray[i])
{
printf("token: %s\n", tokenArray[i]);
i++;
tokenArray[i] = strtok(NULL, " \t");
numOfToken++;
}
data = (int *) malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
printf("data\n");
for(i=0;i<numOfToken;i++){
printf(" %d\n",data[i]);
}
system("PAUSE");
return 0;
}
void strInput (char str[], int maxChars)
{
char garbage;
int k=0;
str[0]='\0';
printf("Please type a string of whole numbers (intigers).\n\n");
while ((k<80) && ((str[k] = getchar()) != '\n'))
k++;
/* Clears the keyboard buffer. */
if (k==80)
while((garbage = getchar()) != '\n')
;
/* Place null at the end of the line read in from user */
str[k]='\0';
printf("str after input is: %s\n\n", str);
}
void custatoi(char* tokenArray[], int * data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
At the end of the strtok loop, tokenArray will be set to NULL. You then pass it to custatoi, which presumably crashes when it tries to dereference it.
Note that tokenArray is not an array of strings; it's just a single string pointer (or a pointer to an array of characters). If you want to accumulate the tokens into an array, you'll have to create a separate array for that purpose.
The main problem is that custatoi() expects to work with an array of pointers to char, while tokenArray in main() is a mere pointer to char. The original code never collects all pointers to tokens in the input string into an array that custatoi() expects, there isn't such an array in the original code.
Please study the fixed code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#define StrSZE 81
void custatoi(char* tokenArray[], int* data, int numOfTok);
int main(void)
{
char str[StrSZE];
char** tokenArray;
int numOfToken = 0, i;
int* data;
//strInput(str, maxChars);
strcpy(str, "1 345 44 23");
tokenArray = malloc(sizeof(char*));
tokenArray[numOfToken] = strtok(str, " \t");
while (tokenArray[numOfToken] != NULL)
{
printf("token: %s\n", tokenArray[numOfToken]);
numOfToken++;
tokenArray = realloc(tokenArray, sizeof(char*) * (numOfToken + 1));
tokenArray[numOfToken] = strtok(NULL, " \t");
}
data = malloc(numOfToken * sizeof(int));
custatoi(tokenArray, data, numOfToken);
for (i = 0; i < numOfToken; i++)
printf("data[%d]=%d\n", i, data[i]);
return 0;
}
void custatoi(char* tokenArray[], int* data, int numOfTok)
{
int i;
for (i=0; i < numOfTok; i++)
data[i] = atoi(tokenArray[i]);
}
Output (idone):
token: 1
token: 345
token: 44
token: 23
data[0]=1
data[1]=345
data[2]=44
data[3]=23

Using strtok in c

I need to use strtok to read in a first and last name and seperate it. How can I store the names where I can use them idependently in two seperate char arrays?
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char * test;
test = strtok (str," ");
while (test != NULL)
{
printf ("%s\n",test);
test= strtok (NULL, " ");
}
return 0;
}
Here is my take at a reasonably simple tokenize helper that
stores results in a dynamically growing array
null-terminating the array
keeps the input string safe (strtok modifies the input string, which is undefined behaviour on a literal char[], at least I think in C99)
To make the code re-entrant, use the non-standard strtok_r
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** tokenize(const char* input)
{
char* str = strdup(input);
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
char* tok=strtok(str," ");
while(1)
{
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = tok? strdup(tok) : tok;
if (!tok) break;
tok=strtok(NULL," ");
}
free(str);
return result;
}
int main ()
{
char** tokens = tokenize("test string.");
char** it;
for(it=tokens; it && *it; ++it)
{
printf("%s\n", *it);
free(*it);
}
free(tokens);
return 0;
}
Here is a strtok-free reimplementation of that (uses strpbrk instead):
char** tokenize(const char* str)
{
int count = 0;
int capacity = 10;
char** result = malloc(capacity*sizeof(*result));
const char* e=str;
if (e) do
{
const char* s=e;
e=strpbrk(s," ");
if (count >= capacity)
result = realloc(result, (capacity*=2)*sizeof(*result));
result[count++] = e? strndup(s, e-s) : strdup(s);
} while (e && *(++e));
if (count >= capacity)
result = realloc(result, (capacity+=1)*sizeof(*result));
result[count++] = 0;
return result;
}
Do you need to store them separately? Two pointers into a modified char array will yield two separate perfectly usable strings.
That is we transform this:
char str[] ="test string.";
Into this:
char str[] ="test\0string.";
^ ^
| |
char *s1 ----- |
char *s2 -----------
.
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="test string.";
char *firstname = strtok(str, " ");
char *lastname = strtok(NULL, " ");
if (!lastname)
lastname = "";
printf("%s, %s\n", lastname, firstname);
return 0;
}
What about using strcpy:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_NAMES 2
int main ()
{
char str[] ="test string.";
char *names[MAX_NAMES] = { 0 };
char *test;
int i = 0;
test = strtok (str," ");
while (test != NULL && i < MAX_NAMES)
{
names[i] = malloc(strlen(test)+1);
strcpy(names[i++], test);
test = strtok (NULL, " ");
}
for(i=0; i<MAX_NAMES; ++i)
{
if(names[i])
{
puts(names[i]);
free(names[i]);
names[i] = 0;
}
}
return 0;
}
It contains much clutter to maintain a complete program and clean its resources, but the main point is to use strcpy to copy each token into its own string.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char** split(const char *str, const char *delimiter, size_t *len){
char *text, *p, *first, **array;
int c;
char** ret;
*len = 0;
text=strdup(str);
if(text==NULL) return NULL;
for(c=0,p=text;NULL!=(p=strtok(p, delimiter));p=NULL, c++)//count item
if(c==0) first=p; //first token top
ret=(char**)malloc(sizeof(char*)*c+1);//+1 for NULL
if(ret==NULL){
free(text);
return NULL;
}
strcpy(text, str+(first-text));//skip until top token
array=ret;
for(p=text;NULL!=(p=strtok(p, delimiter));p=NULL){
*array++=p;
}
*array=NULL;
*len=c;
return ret;
}
void free4split(char** sa){
char **array=sa;
if(sa!=NULL){
free(array[0]);//for text
free(sa); //for array
}
}
int main(void){
char str[] ="test string.";
char **words;
size_t len=0;
int i;
words = split(str, " \t\r\n,.", &len);
/*
for(char **wk = words; *wk ;wk++){
printf("%s\n", *wk);
}
*/
for(i = 0;i<len;++i){
printf("%s\n", words[i]);
}
free4split(words);
return 0;
}
/* result:
test
string
*/
Copy the results from strtok to a new buffer using a function such as
/*
* Returns a copy of s in freshly allocated memory.
* Exits the process if memory allocation fails.
*/
char *xstrdup(char const *s)
{
char *p = malloc(strlen(s) + 1);
if (p == NULL) {
perror("memory allocation failed");
exit(1);
}
strcpy(p, s);
return p;
}
Don't forget to free the return values when you're done with them.
IMO, you don't need (and probably don't want) to use strtok at all (as in, "for this, or much of anything else"). I think I'd use code something like this:
#include <string.h>
#include <stdlib.h>
static char *make_str(char const *begin, char const *end) {
size_t len = end-begin;
char *ret = malloc(len+1);
if (ret != NULL) {
memcpy(ret, begin, len);
ret[len]='\0';
}
return ret;
}
size_t tokenize(char *tokens[], size_t max, char const *input, char const *delims) {
int i;
char const *start=input, *end=start;
for (i=0; *start && i<max; i++) {
for ( ;NULL!=strchr(delims, *start); ++start)
;
for (end=start; *end && NULL==strchr(delims, *end); ++end)
;
tokens[i] = make_str(start, end);
start = end+1;
}
return i;
}
#ifdef TEST
#define MAX_TOKENS 10
int main() {
char *tokens[MAX_TOKENS];
int i;
size_t num = tokenize(tokens, MAX_TOKENS, "This is a longer input string ", " ");
for (i=0; i<num; i++) {
printf("|%s|\n", tokens[i]);
free(tokens[i]);
}
return 0;
}
#endif
U can do something like this too.
int main ()
{
char str[] ="test string.";
char * temp1;
char * temp2;
temp1 = strtok (str," ");
temp2 = strchr(str, ' ');
if (temp2 != NULL)
temp2++;
printf ("Splitted string :%s, %s\n" , temp1 , temp2);
return
}

Resources