insert strtok results into char* (increased dynamic) - c

I'm loosing my mind.
I want to split string (char* text) with spaces and insert the string results into array and return this array.
I have the following method in C
char *read_command(char *text)
{
int index=0;
char *res=NULL;
char *command= (char*)malloc(strlen(text)+1);
strcpy(command, text);
char *tok = strtok(command, " ");
while(tok!=NULL && index ==0)
{
res = (char*)realloc(res, sizeof(char)*(index+1));
char *dup = (char*)malloc(strlen(tok)+1);
strcpy(dup, tok);
res[index++] = dup; //Error here
tok = strtok(NULL, " ");
}
res[index++]='\0';
return res;
}
from main method
char *input="read A B C";
char *command = read_command(input);
Thank you

You are using a wrong type to calculate the size in this call:
res = realloc(res, sizeof(char)*(index+1));
You need to use char*, not char, with sizeof, like this:
res = realloc(res, sizeof(char*)*(index+1));
Since your code returns a pointer to C strings (represented as char*) the return type should be char**.
You need to remove the index == 0 condition from the while loop, otherwise it wouldn't go past the initial iteration.
This assignment
res[index++]='\0';
should be
res[index++]=NULL;
You also need to call free(command) before returning the results to the caller. Finally, you should not cast results of malloc in C.
Here is your code after the fixes above:
char **read_command(char *text) {
int index=0;
char **res=NULL;
char *command= malloc(strlen(text)+1);
strcpy(command, text);
char *tok = strtok(command, " ");
while(tok!=NULL) {
res = realloc(res, sizeof(char*)*(index+1));
char *dup = malloc(strlen(tok)+1);
strcpy(dup, tok);
res[index++] = dup;
tok = strtok(NULL, " ");
}
// Need space to store the "terminating" NULL
// Thanks, BLUEPIXY, for pointing this out.
res = realloc(res, sizeof(char*)*(index+1));
res[index]=NULL;
free(command);
return res;
}
Demo on ideone.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **read_command(const char *text){
int index=0;
char **res=NULL;
char *command= malloc(strlen(text)+1);
strcpy(command, text+strspn(text, " \t\n"));//strspn for skip space from top
char *tok = strtok(command, " ");
res = realloc(res, sizeof(char*)*(index+1));
while(tok!=NULL){
res[index++] = tok;
res = realloc(res, sizeof(char*)*(index+1));
tok = strtok(NULL, " ");
}
res[index++]=NULL;
return res;
}
int main(void){
char *input="read A B C";
char **command = read_command(input);
int i;
for(i=0;command[i]!=NULL;++i){
printf("s[%d]=%s\n", i, command[i]);
}
free(command[0]);//for free command of read_command
free(command);//for free res of read_command,,
return 0;
}

Related

Function to split a string and return every word in the string as an array of strings

I am trying to create a function that will accept a string, and return an array of words in the string. Here is my attempt:
#include "main.h"
/**
* str_split - Splits a string
* #str: The string that will be splited
*
* Return: On success, it returns the new array
* of strings. On failure, it returns NULL
*/
char **str_split(char *str)
{
char *piece, **str_arr = NULL, *str_cpy;
int number_of_words = 0, i;
if (str == NULL)
{
return (NULL);
}
str_cpy = str;
piece = strtok(str_cpy, " ");
while (piece != NULL)
{
if ((*piece) == '\n')
{
piece = strtok(NULL, " ");
continue;
}
number_of_words++;
piece = strtok(NULL, " ");
}
str_arr = (char **)malloc(sizeof(char *) * number_of_words);
piece = strtok(str, " ");
for (i = 0; piece != NULL; i++)
{
if ((*piece) == '\n')
{
piece = strtok(NULL, " ");
continue;
}
str_arr[i] = (char *)malloc(sizeof(char) * (strlen(piece) + 1));
strcpy(str_arr[i], piece);
piece = strtok(NULL, " ");
}
return (str_arr);
}
Once I compile my file, I should be getting:
Hello
World
But I am getting:
Hello
Why is this happening? I have tried to dynamically allocate memory for the new string array, by going through the copy of the original string and keeping track of the number of words. Is this happening because the space allocated for the array of strings is not enough?
The code seems fine overall, with just some issues:
You tried to copy str, as strtok modifies it while parsing.
This is the right approach. However, the following line is wrong:
str_cpy = str;
This is not a copy of strings, it is only copying the address of the string. You can use strdup function here.
Also, you need to return the number of words counted otherwise the caller will not know how many were parsed.
Finally, be careful when you define the string to be passed to this function. If you call it with:
char **arr = str_split ("Hello World", &nwords);
Or even with:
char *str = "Hello World";
char **arr = str_split (str, &nwords);
The program will crash as str here is read-only (see this).
Taking care of these, the program should work with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/**
* str_split - Splits a string
* #str: The string that will be splited
*
* Return: On success, it returns the new array
* of strings. On failure, it returns NULL
*/
char **str_split(char *str, int *number_of_words)
{
char *piece, **str_arr = NULL, *str_cpy = NULL;
int i = 0;
if (str == NULL)
{
return (NULL);
}
str_cpy = strdup (str);
piece = strtok(str_cpy, " ");
while (piece != NULL)
{
if ((*piece) == '\n')
{
piece = strtok(NULL, " ");
continue;
}
(*number_of_words)++;
piece = strtok(NULL, " ");
}
str_arr = (char **)malloc(sizeof(char *) * (*number_of_words));
piece = strtok(str, " ");
for (i = 0; piece != NULL; i++)
{
if ((*piece) == '\n')
{
piece = strtok(NULL, " ");
continue;
}
str_arr[i] = (char *)malloc(sizeof(char) * (strlen(piece) + 1));
strcpy(str_arr[i], piece);
piece = strtok(NULL, " ");
}
if (str_cpy)
free (str_cpy);
return (str_arr);
}
int main ()
{
int nwords = 0;
char str[] = "Hello World";
char **arr = str_split (str, &nwords);
for (int i = 0; i < nwords; i++) {
printf ("word %d: %s\n", i, arr[i]);
}
// Needs to free allocated memory...
}
Testing:
$ gcc main.c && ./a.out
word 0: Hello
word 1: World

Storing tokens from 1D char array to char** array

I am trying to write a program that will dynamically allocate enough space to store all the words in a 1D char array separated by a space.
ex:
char *literal = "The quick brown fox";
char **words = { "The", "quick", "brown", "fox" };
The program I wrote keeps segfaulting when trying to strncpy(str[buff_ptr],tok,strlen(tok));
I will post my code bellow:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *mutableString(char *lit) {
int size = strlen(lit);
char *str = (char *)malloc(sizeof(char) * size);
strncpy(str, lit, size + 1);
return str;
}
int numTokens(char *str, const char *DELIM) {
char* clone = (char*)malloc(sizeof(char*));
strncpy(clone, str, strlen(str) + 1);
int count = 0;
for (char *tok = strtok(clone, " "); tok != NULL; tok = strtok(NULL, " "))
count++;
free(clone);
return count;
}
char **tokenize(char *str, const char *DELIM) {
printf("tokenize-------------------------\n");
int size = numTokens(str, DELIM);
//allocate space on heap for buffer
char **buff = (char **)malloc(size * sizeof(char *));
//get first word
char *tok = strtok(str, DELIM);
int buff_ptr = 0;
while (tok != NULL) {
strncpy(buff[buff_ptr], tok, strlen(tok) + 1);
printf("buff[%d]%s\n", buff_ptr, buff[buff_ptr]);
//increment to next word for storage
buff_ptr++;
//find next word in string
tok = strtok(NULL, DELIM);
}
for (int i = 0; i < size; i++) {
printf("%s\n", buff[i]);
}
//return 2D pointer
return buff;
}
int main() {
char *literal = "some literal string.";
//convert string to mutable string for strtok
char *str = mutableString(literal);
//set 2D pointer equal to the pointer address returned
char **no_spaces_str = tokenize(str, " ");
printf("%s\n", str);
for (int i = 0; i < numTokens(str, " "); i++) {
printf("%s\n", no_spaces_str[i]);
}
//free heap allocated memory
free(str);
free(no_spaces_str);
return 0;
}
Please see attachment of lldb stack variables:
Within the function mutableString there is dynamically allocated the character array str that does not contain a string
char* mutableString(char* lit){
int size = strlen(lit);
char* str = (char*)malloc(sizeof(char)*size);
strncpy(str,lit,size);
return str;
}
So other functions invoke undefined behavior as for example in this for loop
int numTokens(char* str, const char* DELIM){
int count = 0;
for(; *str != '\0'; str++)
//...
Moreover if the array contained a string nevertheless the function numTokens is incorrect because for example it returns 0 when a passed string contains only one word.
Also in the function tokenize
strncpy(buff[buff_ptr],tok,strlen(tok));
there are used uninitialized pointers buff[buff_ptr] allocated like.
char **buff = (char**)malloc(size*sizeof(char*));
And again you are trying to copy strings without including the terminating zero character '\0; using eth functions strncpy.
So this call in main
printf("%s\n",no_spaces_str[i]);
also will invoke undefined behavior.
This is the corrected version of the code above
When you copying string you should add 1 char for '\0'
int size = strlen(lit)+1;
Tokens buffer size should be size+1
int size = numTokens(str, DELIM)+1;
Strncpy is not required strncpy(buff[buff_ptr], tok, strlen(tok) + 1);
you already copied string char* str = mutableString(literal);
just point to n-th buffer every next token buff[buff_ptr]=tok;
for (int i = 0; i<numTokens(str, " "); i++){
printf("%s\n", no_spaces_str[i]);
}
This code wouldn't work correctly. strtok manipulates the string you pass in and returns a pointer to it, so no memory is allocated.
so all spaces will be replaced by '\0'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#pragma warning(push)
#pragma warning(disable : 4996)
char* mutableString(char* lit){
int size = strlen(lit)+1;
char* str = (char*)malloc(sizeof(char)*size);
strncpy(str, lit, size);
return str;
}
int numTokens(char* str, const char* DELIM){
int count = 0;
for (; *str != '\0'; str++)
{
if (*str == ' ')
count++;
}
return count;
}
char** tokenize(char* str, const char* DELIM){
printf("tokenize-------------------------\n");
int size = numTokens(str, DELIM)+1;
//allocate space on heap for buffer
char **buff = (char**)malloc((size)*sizeof(char*));
//get first word
char* tok = strtok(str, DELIM);
int buff_ptr = 0;
while (tok != NULL){
buff[buff_ptr]=tok;
printf("buff[%d]%s\n", buff_ptr, buff[buff_ptr]);
//increment to next word for storage
buff_ptr++;
//find next word in string
tok = strtok(NULL, DELIM);
}
for (int i = 0; i<size; i++){
printf("%s\n", buff[i]);
}
//return 2D pointer
return buff;
}
int main(){
char* literal = "some literal string.";
//convert string to mutatable string for strtok
char* str = mutableString(literal);
//set 2D pointer equal to the pointer addres returned
char** no_spaces_str = tokenize(str, " ");
printf("%s\n", str);
for (int i = 0; i<numTokens(str, " "); i++){
printf("%s\n", no_spaces_str[i]);
}
//free heap allocated memory
free(str);
free(no_spaces_str);
return 0;
}
results
tokenize-------------------------
buff[0]some
buff[1]literal
buff[2]string.
some
literal
string.
some
char* mutableString(char* lit){
int size = strlen(lit)+1;
char* str = (char*)malloc(sizeof(char)*size);
strncpy(str,lit,size);
return str;
}
int numTokens(char* str, const char* DELIM){
int size = strlen(str)+1;
char* clone = (char*)malloc(sizeof(char)*size);
strncpy(clone,str,size);
int count = 0;
for(char* tok = strtok(clone," "); tok != NULL; tok=strtok(NULL, " "))
count++;
free(clone);
return count;
}
char** tokenize(char* str, const char* DELIM){
int size = strlen(str)+1;
char* clone = (char*)malloc(sizeof(char)*size);
strncpy(clone,str,size);
// printf("tokenize-------------------------\n");
int size = numTokens(str, DELIM);
//allocate space on heap for buffer
char **buff = (char**)calloc(size,sizeof(char*));
//get first word
char* tok = strtok(clone,DELIM);
int buff_ptr = 0;
while(tok != NULL){
// printf("token%d:%s\n",buff_ptr,tok);
buff[buff_ptr] = (char*)malloc(sizeof(char)*strlen(tok)+1);
strncpy(buff[buff_ptr],tok,strlen(tok)+1);
//increment to next word for storage
buff_ptr++;
//find next word in string
tok = strtok(NULL, DELIM);
}
//return 2D pointer
free(clone);
return buff;
}
int main(){
char* literal = "some literal string.";
//convert string to mutatable string for strtok
char* str = mutableString(literal);
//set 2D pointer equal to the pointer addres returned
char** no_spaces_str = tokenize(str, " ");
int num_words = numTokens(str," ");
char* oneD = (char*)calloc(strlen(str)+1,sizeof(char));
for(int i = 0;i<num_words;i++){
strncat(oneD,no_spaces_str[i],strlen(no_spaces_str[i])+1);
printf("%s\n",oneD);
}
//free heap allocated memory
free(str);
free(no_spaces_str);
free(oneD);
return 0;
}
Is solution to my problem. Thanks to all those who commented and helped me understand dynamic memory better.
Apart from the #Vlad from Moscow mentioned points,
malloc return values must not be type-casted Do I cast the result of malloc?
I tried to clean up the code find the snippet below, DEMO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char** buff;
int size;
}Array_2d;
char* mutableString(const char* lit){
int size = strlen(lit);
char* str = malloc(size);
strncpy(str,lit,size+1);
return str;
}
int getNextWordLength(const char* str){
int index = 0;
while(*str && (*str != ' ')){
//printf("%c",*str);
++index;
++str;
}
return index;
}
int numTokens(const char* str){
int count = 0;
for(; *str != '\0'; str++)
{
if(*str == ' ')
count++;
}
return count;
}
void tokenize(const char* str, const char *DELIM, Array_2d *array){
int len = strlen(str)+1;
if(!str && !len){
array->buff = 0;
array->size = 0;
}
int number_of_words = numTokens(str)+1;
//allocate space on heap for buffer
char **buff = (char**)malloc(number_of_words*sizeof(char*));
int index = 0;
do{
//get first word
int word_length = getNextWordLength(str);
//To compensate null terminal
buff[index] = malloc(word_length+1);
strncpy(buff[index], str,word_length);
buff[index][word_length+1] = '\0';
str += word_length+1;
++index;
}while(index < number_of_words);
//update return value
array->buff = buff;
array->size = number_of_words;
}
int main(){
char* literal = "hello world this is test";
//convert string to mutatable string for strtok
char* str = mutableString(literal);
printf("Complete String is : %s\n",str);
Array_2d array;
// set 2D pointer equal to the pointer addres returned
tokenize(str, " ",&array);
printf("Tokenized String\n");
for(int i=0;i<array.size;i++){
printf("%s\n",array.buff[i]);
}
free(str);
for(int i =0;i< array.size; ++i)
free(array.buff[i]);
free(array.buff);
return 0;
}

how to substitute substring with different length in C?

Situation as following:
In the first line input a string, then the following lines are 'command'. 2 types of command 'p' and 's', 'p' means printing the string, 's' means substitution.
e.g. Input a string aaabbbcccqwerdd then input sbqwerbkkk
(s means substitution, b acts as a delimiter, therefore it means replacing qwer in the string with kkk)
The expected result should be aaabbbccckkkdd, but instead I got aaabbbccckkkrdd
Any help?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1023
int main() {
char str[MAXLEN];
scanf("%s", str);
char command[MAXLEN];
while (scanf("%s", command) != EOF) {
if (command[0] == 'p') {
printf("%s\n", str); }
else if (command[0] == 's') {
char delimiter[] = {"0"};
strncpy(delimiter, command+1, 1);
char *a = command;
a = strtok(command, delimiter);
a = strtok(NULL, delimiter);
char *b = command;
b = strtok(NULL, delimiter);
int alength = strlen(a);
int blength = strlen(b);
char *bereplaced = strstr(str, a);
if (bereplaced == NULL) {
continue; }
int aindex = bereplaced - str;
strncpy(str + aindex, b, blength);
}
}
return 0;
}
Many things can go wrong here but the main issue is copying from from source string on to itself, there can be memory overlap. Instead declare a new buffer for the result for find/replace operation.
You can define a separate find_replace function as follows:
char* find_replace(const char* src, const char* find, const char* replace)
{
if (!src) return NULL;
char* find_ptr = strstr(src, find); if (!find_ptr) return NULL;
int find_start = find_ptr - src;
int find_length = strlen(find);
char* result = malloc(strlen(src) + strlen(replace) + 1);
strncpy(result, src, find_start);
strcpy(result + find_start, replace);
strcat(result, find_ptr + find_length);
return result;
}
int main()
{
char source[] = "aaabbbcccqwerdd";
char command[] = "sbqwerbkkk";
if (command[0] != 's') return 0;
char delimiter[] = { "0" };
delimiter[0] = command[1];
char* find = strtok(command, delimiter); if (!find) return 0;
find = strtok(NULL, delimiter); if (!find) return 0;
char* replace = strtok(NULL, delimiter); if (!replace) return 0;
char* result = find_replace(source, find, replace);
if (!result) return 0;
printf("%s\n", result);
free(result);
return 0;
}
Here is another solution. It does the substitution directly into the input string by:
Use memmove to move the trailing part of the orginal string to its final location
Use strncpy to copy the substitute substring to its final location
Like:
#include <stdio.h>
#include <string.h>
#define MAXLEN 1023
int main(void)
{
char str[MAXLEN] = "aaabbbcccqwerdd";
char command[MAXLEN] = "sbqwerbkkk";
printf("COMMAND : %s\n", command);
printf("TEXT BEFORE : %s\n", str);
char* pfind = command + 2; // skip initial sb
char* psub = strchr(pfind, 'b'); // find delimiter
*psub = '\0'; // terminate replace string
++psub; // point to substitute substring
size_t flen = strlen(pfind); // calculate length
size_t slen = strlen(psub); // calculate length
char* p = strstr(str, pfind); // find location of replace string
size_t sc = strlen(p); // calculate length
memmove(p + slen, p + flen, sc - flen + 1); // Move trailing part
strncpy(p, psub, slen); // Put in substitute substring
printf("TEXT AFTER : %s\n", str);
return 0;
}
Output:
COMMAND : sbqwerbkkk
TEXT BEFORE : aaabbbcccqwerdd
TEXT AFTER : aaabbbccckkkdd
Disclamer
In order to keep the code example short, the above code blindly trust that the command and the original string form a legal substitution and that there are sufficient memory for the result.
In real code, you need to check that. For instance check that strchr and strstr doesn't return NULL.

How to extract words from parentheses in C language?

I am trying to extract words from a string like this:
(octopus kitten) (game cake) (soccer football)
I attempted doing this with the help of strtok (I do strcpy just for not modifying the original token/string, also used memcpy, but it does the same in my case).
Main function:
int main(int argc, char * argv[]) {
char row[] = "(octopus kitten) (game cake) (soccer football)";
char * pch;
pch = strtok(row, "(");
while (pch != NULL) {
pch[strcspn(pch, ")")] = '\0';
print_word(pch);
pch = strtok(NULL, "(");
}
return 0;
}
Function for getting and printing each word:
void get_and_print_word(char str[]) {
char r[4000];
// for not modifying the original string
strcpy(r, str);
char * c = strtok(r, " ");
for (int i = 0; i < 2; i++) {
printf("%s\n", c);
c = strtok(NULL, " ");
}
}
It works absolutely fine with a first iteration, but after pch starts to point to another adress of memory (but it should point to the adress of letter "g").
It works absolutely fine (it's just printing string within the brackets) if we remove get_and_print_word(pch):
int main(int argc, char * argv[]) {
char row[] = "(octopus kitten) (game cake) (soccer football)";
char * pch;
pch = strtok(row, "(");
while (pch != NULL) {
pch[strcspn(pch, ")")] = '\0';
printf("%s\n", pch);
pch = strtok(NULL, "(");
}
return 0;
}
But that's not what I want to do, I need to get each word, not just a string of two words and space between them.
Using pch = strtok(NULL, " )(") is also not appropriate in my case, cause I need to store each pair of words (each word, of couse, should be a separate string) in some individual
struct, so I definitely need this function.
How to solve this issue and why it works like this?
Why not use regular expression :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <regex.h>
int main (int argc, char *argv[])
{
int err;
regex_t preg;
const char *str_request = argv[1];
const char *str_regex = argv[2];
err = regcomp (&preg, str_regex, REG_EXTENDED);
if (err == 0) {
int match;
size_t nmatch = 0;
regmatch_t *pmatch = NULL;
nmatch = preg.re_nsub;
pmatch = malloc (sizeof (*pmatch) * nmatch);
char *buffer;
if (pmatch) {
buffer = (char *) str_request;
match = regexec (&preg, buffer, nmatch, pmatch, 0);
while (match == 0) {
char *found = NULL;
size_t size ;
int start, end;
start = pmatch[0].rm_so;
end = pmatch[0].rm_eo;
size = end - start;
found = malloc (sizeof (*found) * (size + 1));
if (found) {
strncpy (found, &buffer[start], size);
found[size] = '\0';
printf ("found : %s\n", found);
free (found);
}
//searching next occurence
match = regexec (&preg, (buffer += end), nmatch, pmatch, 0);
}
regfree (&preg);
free (pmatch);
}
}
return 0;
}
[puppet#damageinc regex]$ ./regex "(octopus kitten) (game cake) (soccer football)" "([a-z]+)"
found : octopus
found : kitten
found : game
found : cake
found : soccer
found : football

break a string into 'first' and 'second'

I have read through countless strtok posts, even copied some directly in their entirety into a new int main, but I can't figure out how to create the functions get_first and get_second.
get_first("This is a sentence."); //returns "This"
get_rest("This is a sentence."); //returns "is"
This is what I have so far, I have had nothing but trouble with strtok, but I don't know what else to use.
#include <stdio.h>
#include <string.h>
char * get_first(char * string) {
string = strtok(string, " ");
return string;
}
char * get_second(char * string) {
string = strtok(string, " ");
string = strtok(NULL, " ");
return string;
}
int main(int argc, char * argv[]) {
char * test_string = "This is a sentence.";
char * first = get_first(test_string);
char * second = get_second(test_string);
printf("%s\n", first);
printf("%s\n", second);
}
Getting no faults compiling with gcc -g -Wall, but it always seg faults. I think I have tried every permutation of char c[] and char * c there is.
strtok changes the string. (but String literals are not allowed to change.)
So create a copy.
Do the following:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * get_first(const char *string){
char *clone = strdup(string);//create copy, strdup is non standard. malloc and copy.
char *token = strtok(clone, " ");
if(token)
token = strdup(token);
free(clone);
return token;
}
char * get_second(const char *string) {
char *clone = strdup(string);
char *token = strtok(clone, " ");
if(token && (token = strtok(NULL, " ")))
token = strdup(token);
free(clone);
return token;
}
int main(void) {
char * test_string = "This is a sentence.";
char * first = get_first(test_string);
char * second = get_second(test_string);
printf("%s\n", first);
printf("%s\n", second);
free(first);
free(second);
}

Resources