I want to write a function that processes a string that looks like this:
|1,2,3,4|(1->2),(2->3),(3->1)|
The result should be a breaking down of the string into these strings:
1
2
3
4
(1->2)
(2->3)
(3->2)
This is my code:
int processPart(char*** dest, char* from) //Processes a half at a time
{
int len = 0;
char* cutout = strtok(from, ",");
while(cutout)
{
(*dest) = (char**)realloc(dest, (len + 1) * sizeof(char*)); <<<<<<<
(*dest)[len] = (char*)calloc(strlen(cutout) + 1, sizeof(char));
memcpy((*dest)[len], cutout, strlen(cutout));
cutout = strtok(NULL, ",");
len++;
}
return len;
}
void processInput(char*** vertices, char*** edges, char* input, int* sizev, int* sizee)
{
int vlen = 0, elen = 0;
char* string = input + 1;
char* raw_vertices;
char* raw_edges;
string[strlen(string)] = '\0';
raw_vertices = strtok(string, "|");
raw_edges = strtok(NULL, "|");
*sizev = processPart(vertices, raw_vertices); //First the vertices
*sizee = processPart(edges, raw_edges); //Then the edges
}
int main()
{
char* in = stInput(); //input function
char** c = NULL, **b = NULL;
int a, d, i;
processInput(&c, &b, in, &a, &d);
for(i = 0; i < a; i++)
{
printf("%s\n", c[i]);
}
printf("++++++++++++++++");
for(i = 0; i < d; i++)
{
printf("%s\n", b[i]);
}
return 0;
}
However, I get a corruption of the heap at the line marked by <<<<<<<
Anyone knows what my mistake is?
In the erroneous line
(*dest) = (char**)realloc(dest, (len + 1) * sizeof(char*));
a * is missing before the dest argument. You could have spotted this easier if you hadn't cluttered the expression with the useless cast. I'd write
*dest = realloc(*dest, (len + 1) * sizeof**dest);
- that way we can see better the matching of first argument and left operand of the assignment.
Related
I'm trying to split this string:
this is a text file
looking for the word cat
the program should print also cats
and crat and lcat but it shouldn’t
print the word caats
into a two dimensional arrays such that every line in the text is a line in the array.
For example:
lines[0][0] = 't'
lines[0][1] = 'h'
and so on. For now, this is my code:
void print_lines(char txt[]){
char lines[SIZE][SIZE];
int num_of_lines = fill_lines(txt, lines);
printf("lines: %d\n",num_of_lines );
int i;
for (i = 0; i < num_of_lines; i++)
{
printf("%s\n", lines[i]);
}
}
int fill_lines(char txt[], char lines[][]){
char copy[strlen(txt)];
memcpy(copy, txt, strlen(txt));
char *line = strtok(copy, "\n");
int i = 0;
while(line != NULL){
strcpy(lines[i][0], line);
line = strtok(NULL, "\n");
i++
}
return i + 1;
}
The problem I'm currently dealing with is an error in strcpy(lines[i], line) that reads:
expression must be a pointer to a complete object type
I have also tried memcpy(lines[i], line, strlen(line)).
Any help would be much appreciated.
I think this should work for you
Here I used '\n' as a delimiter
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
char **str_split(char *a_str, const char a_delim)
{
char **result = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
/* Count how many elements will be extracted. */
while (*tmp)
{
if (a_delim == *tmp)
{
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
if (result)
{
size_t idx = 0;
char *token = strtok(a_str, delim);
while (token)
{
assert(idx < count);
*(result + idx++) = strdup(token);
token = strtok(0, delim);
}
assert(idx == count - 1);
*(result + idx) = 0;
}
return result;
}
int main()
{
char text[] = "this is a text file\nlooking for the word cat\nthe program should print also cats\nand crat and lcat but it shouldn’t\nprint the word caats";
char **tokens;
printf("ORIGINAL TEXT:\n%s\n\n", text);
tokens = str_split(text, ',');
if (tokens)
{
int i;
for (i = 0; *(tokens + i); i++)
{
printf("%s\n", *(tokens + i));
free(*(tokens + i));
}
printf("\n");
free(tokens);
}
return 0;
}
I have a string like this:
"monday,wednesday,friday"
And I'd like to save this into an array of char arrays (~array of strings).
char **splitString(char *string, int size, char delimiter)
{
char **ptr = (char **)malloc(size * sizeof(char *));
int i = 0;
ptr[i] = strtok(string, &delimiter);
while (ptr[i] != NULL)
{
ptr[++i] = strtok(NULL, &delimiter);
}
return ptr;
}
Managed to do it with the code above, but since it always checks the current tokenized string it does not stop with the last one and reads an additional NULL. Printing out the array I get:
The 0. element is: monday
The 1. element is: wednesday
The 2. element is: friday
The 3. element is: (null)
Is there a concise and simple way to know when the loop is reaching the last element?
Well, you can accomplish your goal, just by changing each , to \0 and setting an array of pointers to the first character of the string, and to each character after a ,. Somehow like:
#include<stdio.h>
#include<stdlib.h>
char **split_string(char *str, int *size) {
int i;
*size = 1;
printf("size = %d\n", *size);
char **array = malloc(*size * sizeof(char *));
array[0] = &str[0];
for (i = 1; str[i] != 0; i++) {
if (str[i] == ',') {
(*size)++;
printf("size = %d\n", *size);
array = realloc(array, sizeof(char *) * (*size));
array[(*size) - 1] = &str[i + 1];
str[i] = '\0';
}
}
return array;
}
int main() {
char str[] = "one,two,three";
int size;
char **array = split_string(str, &size);
for (int i=0; i < size; i++) {
printf("%s\n", array[i]);
}
return 0;
}
Use something like this
char **splitString(char *string, int size, char delimiter)
{
char **ptr = (char **)malloc(size * sizeof(char *));
char *p;
int i = 0;
p = strtok(string, &delimiter);
while (p != NULL)
{
ptr[i++] = p;
p = strtok(NULL, &delimiter);
}
return ptr;
}
You can use , as a separator with simple loop :
counter = 0;
counter2;
char thing [][]
char YourString
for(i = 0;i<=20;i++){
if(YourString !=","){
thing[counter][i]=yourString[counter2]
}
else{
counter++;
}
counter2++;
}
I get a segfault the second time this statement runs:
chunks[i].argv[0] = malloc( strlen(token) * sizeof(char *) + 1 );
The code in context is:
/* TODO: modify str_split to do the copying of its input string if it needs to (e.g. if it uses strtok on it), and return a struct that has the number of "chunks" it split out and the list of chunks. */
struct str_list *list_split(char *a_str, const char a_delim) {
char **result = 0;
char **result2 = 0;
size_t count = 0;
char *tmp = a_str;
char *last_comma = 0;
size_t count2 = 0;
char *tmp2 = a_str;
char *last_space = 0;
char delim[2];
delim[0] = a_delim;
delim[1] = 0;
struct str_list *chunks = NULL;
/* Count how many elements will be extracted. */
while (*tmp) {
if (a_delim == *tmp) {
count++;
last_comma = tmp;
}
tmp++;
}
/* Add space for trailing token. */
count += last_comma < (a_str + strlen(a_str) - 1);
/* Add space for terminating null string so caller
knows where the list of returned strings ends. */
count++;
result = malloc(sizeof(char *) * count);
chunks = malloc(sizeof(chunks));
//chunks.size = malloc(sizeof(int));
// counter = (int) count + 1;
//chunks->size = counter;
if (result == NULL) {
printf("Error allocating memory!\n"); //print an error message
return chunks;; //return with failure
}
if (result) {
size_t idx = 0;
char *token = strtok(a_str, delim);
int i = 0;
while (token) {
assert(idx < count);
*(result + idx++) = strdup(token); /* memory leak! how to free() */;
token = strtok(0, delim);;
}
assert(idx == count - 1);
*(result + idx) = 0;
}
chunks->size = (int) count;
chunks->argv = alloc_argv((unsigned) chunks->size);
for (int i = 0; i < 2; i++) { //count is wrong
while (*tmp2) {
if (' ' == *tmp2) {
count2++;
last_space = tmp2;
}
tmp2++;
}
char* token = strtok(result[i], " ");
while (token) {
printf("token: %s\n", token);
printf("size: %d\n", chunks->size);
printf("result: %s\n", result[i]);
printf("i: %d\n", i);
chunks[i].argv[0] = malloc( strlen(token) * sizeof(char *) + 1 );
chunks[i].argv[0] = strdup(token);;
token = strtok(0, " ");
}
}
return chunks;
}
My debugger says nothing interesting. Can you see what is wrong and what should be done? The call to the above function is:
int run_cmd(const char *cmd) {
struct str_list *chunks = list_split(cmd, '|');
struct pipeline *pipe = alloc_pipeline(2); //size is the number of pipelines
for (int i = 0; i < 2; i++) {
printf("i %d", i);
for (int j = 0; j < 1; j++) {
pipe[i].data[j] = chunks[i].argv[j];
}
}
int status = execute_pipeline(pipe);
// free_pipeline(pipe);
// free_str_list(chunks);
return status;
}
The definition of my structs is
struct str_list {
char *name;
int size;
char **argv;
};
struct pipeline {
char *name;
int size;
char **data;
};
This line
chunks = malloc(sizeof(chunks));
That allocates the size of the chunks variable, which is a pointer and is usually only 4 or 8 bytes large (depending on if you're on a 32 or 64 bit system).
A str_list structure is larger than that, which means you will write out of bounds of allocated memory, leading to undefined behavior and most likely a crash.
You seem to be using two of this structure, judging by the loops, which means you need to allocate two full str_list structures, which is simplest done by e.g.
chunks = malloc(2 * sizeof *chunks);
I got a segment fault error at the line with the comments that contains lots of equals signs below.
The function below str_spit, I wrote it because I want to split a string using a specific char, like a comma etc.
Please help.
int str_split(char *a_str, const char delim, char *** result)
{
int word_length = 0;
int cur_cursor = 0;
int last_cursor = -1;
int e_count = 0;
*result = (char **)malloc(6 * sizeof(char *));
char *char_element_pos = a_str;
while (*char_element_pos != '\0') {
if (*char_element_pos == delim) {
char *temp_word = malloc((word_length + 1) * sizeof(char));
int i = 0;
for (i = 0; i < word_length; i++) {
temp_word[i] = a_str[last_cursor + 1 + i];
}
temp_word[word_length] = '\0';
//
*result[e_count] = temp_word;//==============this line goes wrong :(
e_count++;
last_cursor = cur_cursor;
word_length = 0;
}
else {
word_length++;
}
cur_cursor++;
char_element_pos++;
}
char *temp_word = (char *) malloc((word_length + 1) * sizeof(char));
int i = 0;
for (i = 0; i < word_length; i++) {
temp_word[i] = a_str[last_cursor + 1 + i];
}
temp_word[word_length] = '\0';
*result[e_count] = temp_word;
return e_count + 1;
}
//this is my caller function====================
int teststr_split() {
char delim = ',';
char *testStr;
testStr = (char *) "abc,cde,fgh,klj,asdfasd,3234,adfk,ad9";
char **result;
int length = str_split(testStr, delim, &result);
if (length < 0) {
printf("allocate memroy failed ,error code is:%d", length);
exit(-1);
}
free(result);
return 0;
}
I think you mean
( *result )[e_count] = temp_word;//
instead of
*result[e_count] = temp_word;//
These two expressions are equivalent only when e_count is equal to 0.:)
[] has a higher precedence than *, so probably parentheses will solve THIS problem:
(*result)[e_count] = temp_word;
I didn't check for more problems in the code. Hint: strtok() might do your job just fine.
I'm new in programming in C and I got 2 problems. I have two string, then I need to split them into words and find out if both strings contains same words. I will explain it with my code.
Input:
"He said he would do it."
"IT said: 'He would do it.'"
This two string are placed into two arrays. At first I need to parse words from others characters.
Call function:
char ** w1 = parse(s1, &len1);
Variable len counts number of rows (words).
Function parse:
char ** parse(char *w, int * i)
{
int j = 0, y, dupl = 0; //variables for cycles and duplicate flag
char d[] = " <>[]{}()/\"\\+-*=:;~!##$%^&_`'?,.|";
char* token = strtok(w, d);
unsigned len = strlen(token), x;
unsigned plen = len;
char ** f = (char**) malloc(len * sizeof (char*));
while (token != NULL)
{
len = strlen(token);
for (x = 0; x < len; x++)
{
token[x] = tolower(token[x]);
}
for (y = 0; y < *i; y++) //cycle for deleting duplicated words
{
if (equals(token, f[y]) == 1)
{
dupl = 1; break;
}
}
if (dupl == 1)
{
token = strtok(NULL, d);
dupl = 0;
continue;
}
if (len >= plen)
{
f = (char**) realloc(f, (len+1) * sizeof (char*));
plen = len;
}
else
f = (char**) realloc(f, (plen+1) * sizeof (char*));
f[j] = token;
token = strtok(NULL, d);
*i = *i + 1;
j++;
}
free(token);
return f;
}
Ok, now i have 2x 2Darrays, then just sort it (qsort(w1, len1, sizeof (char*), cmp);) and compare it:
for (i = 0; i < len2; i++)
if (equals(w1[i], w2[i]) == 0)
return 0;
Function equals:
int equals(char *w1, char *w2)
{
if (strcmp(w1, w2) == 0)
return 1;
return 0;
}
I know that all of this can be faster, but at first I need to solve my problem. This works for input which I wrote at the beginning, but when I type something long e.g.500 characters, my result is Aborted. I think that the problem is here:
f = (char**) realloc(f, (len+1) * sizeof (char*));
but dunno why.
Second thing is, that I can't free my arrays. This
void Clear (char ** w, int max)
{
int i;
for (i = 0; i < max; i++)
free(w[i]);
free(w);
}
gives me a segmentation fault.
Thanks for your time and I'm sorry for my bad english and bad programming skills.
It seems to have confused the word length and number of words in the parse function in your logic.
char ** f = (char**) malloc(len * sizeof (char*));
I think for example of len in portions of the above are as should be the number of words rather than characters.