Home > OS >  Can only write to first element of char** buffer
Can only write to first element of char** buffer

Time:07-16

I'm quite new to C and am trying to write a function, which will split a string into an array of strings at a specific delimiter. But strangely I can only write at the first index of my char** array of strings, which will be my result. For example if I want to split the following string "Hello;;world;;!" at ;; I get [ "Hello" ] instead of [ "Hello", "world", "!" ]. I can't find my mistake.

#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "strings.h"

int split(char **dest, const char *src, const char *splitStr) {
    char buffer[16384];
    int counter = 0;
    int len = strlen(splitStr);
    int flag = 0;
    int start = 0;
    for (int i = 0; i < strlen(src); i  ) {
        flag = 0;
        if (src[i] == splitStr[0]) {
            for (int j = 1; j < len; j  ) {
                //check if all elements in delimiter are in string
                if (src[i   j] == splitStr[j] && j != (len - 1)) {
                    continue;
                }
                else if(src[i   j] == splitStr[j] && j == (len - 1)) {
                    buffer[i] = '\0';
                    dest[counter] = malloc(sizeof(char) * (i - start   1));
                    strncpy(dest[counter], buffer   start, (i - start));
                    start = i   (len-1)
                    flag = 1;
                    i  = (len - 1);
                    counter  ;
                }
                //if not break
                else {
                    break;
                }
            }
        }
    
        if (i == (strlen(src) - 1)) {
            buffer[i] = src[i];
            buffer[i   1] = '\0';
            counter  ;
            break;
        }
        if (flag == 0) {
            buffer[i] = src[i];
        }
    }
    return counter;
}

A proper function call would look like this:

auto src = "Hello;;world;;!";
auto buffer = (char **)malloc(32);
int count = split(buffer, src, ";;");

The buffer should contain, all the splitted strings, more or less like this: [ "Hello", "world", "!" ]. Currently my result buffer looks like this in the debugger. It appears as only the first element is written into it. Debugging result of buffer after function call

CodePudding user response:

First of all you are not updating the start variable after you have copied the first string.

For simple debugging I would recommend adding some printf statements to see what is going on.

Proper formatting is not to be underestimated to make the code easy to read and easier to debug.

Also it is not clear what the buffer is for, and I think you can do without it.

The tips in the comments are also good. Split the function into smaller pieces and structure your code so it is simple to read.

A suggestion is to write a function to find the index of the next split string and the end of the string. Then you can use that to get the index and length you need to copy.

CodePudding user response:

There are multiple problems in your code:

  • you compute string lengths repeatedly, which may be very inefficient. Instead of testing i < strlen(src) you should write src[i] != '\0'.

  • your test for check a matching delimiter is too complicated. You should use strstr to locate the delimiter string in the remaining portion of the string.

  • strncpy does not do what you think: strncpy(dest[counter], buffer start, (i - start)); should be replaced with memcpy(dest[counter], buffer start, i - start); and you must set the null terminator explicitly: dest[counter][i - start] = '\0'; You should read why you should never use strncpy().

  • it is unclear why you use buffer at all.

Here is a modified version:

#include <stdlib.h>
#include <string.h>

/* if POSIX function strndup() is not defined on your system, use this */
char *strndup(const char *str, size_t n) {
    size_t len;
    for (len = 0; len < n && str[len] != '\0'; len  )
        continue;
    char *s = malloc(len   1);
    if (s != NULL) {
        memcpy(s, str, len);
        s[len] = '\0';
    }
    return s;
}

int split(char **dest, const char *src, const char *splitStr) {
    const char *p = str;
    const char *end;
    int counter = 0;
    size_t len = strlen(splitStr);
    if (len == 0) {
        /* special case */
        while (*p != '\0') {
            dest[counter  ] = strndup(p  , 1);
        }
    } else {
        while ((end = strstr(p, splitStr)) != NULL) {
            dest[counter  ] = strndup(p, end - p);
            p = end   len;
        }
        dest[counter  ] = strdup(p);
    }
    return counter;
}
  • Related