1

I have a C++ function that splits a char array into multiple char arrays when it encounters a delimiter. For some reason, when saving the third split array the program just crashes and sometimes returns an std::bad_alloc exception.

char ** explode(const char * arr, const char delim) {
int start, end, curr=0, count=1;
char ** strings;
//Iegūst explodēto stringu skaitu
for (int i = 0; arr[i] != 0; i++) {
    if (arr[i] == delim && i != 0 && arr[i+1] != 0 && arr[i+1] != delim ) { //Nav pirmais, nav pēdējais, nav pa labi vēlviens delimiters
        count++;
    }
}
strings = new char*[count];
start = 0;
for (int i = 0; arr[i] != 0; i++) {
    if (arr[i] == delim || arr[i+1] == 0) {
        if (arr[i] == delim) {
            end = i;
        } else {
            end = i+1;
        }
        if (end-start < 1) {
            start++;
        } else {
            copystring(arr,strings[curr++],start,end-start);
            start = i+1;
        }
    }
}
for (int i = 0; i < count; i++) {
    cout << strings[i] << endl;
}

return strings;
}

//Pārkopē daļu no pirmā char masīva uz otru, no START pozīcijas, līdz GARUMS garumā
void copystring(const char * from, char *& to, const int start, const int garums) {
    int curr=0;
    if (garums < 1 || start > charlen(from)) {
        return;
    }
    to = new char[garums];
    for (int i = start; i < start+garums && from[i] != 0; i++) {
        to[curr++] = from[i];
    }
    to[curr] = 0;
}

It's hard to tell because it doesn't really tell me at which line everything goes wrong, but I think it happens at

to = new char[garums];

I've tried debugging this line within CodeBlocks, but for some reason when using breakpoints and tracking the variables the applications works fine and executes correctly. It only crashes when running it normally, without debugging...

Also note, that I can't use strings or pretty much any library except fstream and iostream.

EDIT: I tried changing the new char[garums] part to new char[100] and it magically started working. The problem is that I then changed it to new char[10] in which case everything still worked. I even outputted the saved text to the console and it saved everything properly. How could it have saved big words in a char array that is 10 character long (the words I'm testing are longer than 10 characters)? When I changed it to new char[1] however it started crashing again, but again only after the 3rd loop iteration. So it somehow saved the first 2 words in a 1 character long array?

EDIT2: And now it magically started working even with new char[garums]. Something is really wrong here, anyone have any ideas?

Fabis
  • 1,932
  • 2
  • 20
  • 37
  • you might wish to do an execution whilst tracing your `garums` before each `new char[garums]` – danielschemmel Apr 27 '14 at 15:30
  • I think you got the wrong idea of what you want to do. You are receiving a one-dimensional array. And your result as it appears to me should be a two-dimensional array. Your result will have to be an array of char-arrays. If I was you I'd 1) iterate over the input string and store count and position of each delimiter to 2) copy the sub-strings into the two-dimensional result array. – Stefan Falk Apr 27 '14 at 15:59
  • Yes, it is a 2D array because it splits the 1D array into multiple 1D arrays - a 2D array. Also that's pretty much what the function is doing, just for some reason it crashes when trying to initialize the arrays. – Fabis Apr 27 '14 at 16:14

3 Answers3

0

Since I don't know what input data you have I will have to guess:

Here you allocate your pointer array but please note that all the pointers are uninitialized.

strings = new char*[count]

then when you parse the code you use a variable curr which you let run freely so it is not certain that all strings[] have been set to some value or whether curr lands on a number larger than count.

If I were you I would put in a check to make sure that:

a) curr does not exceed count

b) that if curr lands on a value less than count, set the rest of the pointers to nullptr

incarnadine
  • 658
  • 7
  • 19
AndersK
  • 35,813
  • 6
  • 60
  • 86
0

The bug you refer to in your question likely crops up when trying to use the pointer to pointer being returned from the explode function. Some pointers ; If you have to write C code, don't use a mishmash of C/C++, Use the library functions rather than re-inventing the wheel (strncpy in copystring) Your word count was off because you didn't take into account the word between the last delimiter and EOL Below are some minor changes to your code as a complete example :

#include <stdio.h>
#include <strings.h>

void copystring(const char *from, char **to, const int numchars)
{
    if (numchars > 0) {
            *to = new char[numchars];
            strncpy(*to, from, numchars) ;
            (*to)[numchars] = '\0' ;
    }
}

char **explode(const char * buffer, const char delim)
{
    int count = 0 ;

    if (strlen(buffer) > 0) {
            int inword = 0 ;
            int idx = 0 ;
            do {
                    if (buffer[idx] == delim || buffer[idx] == '\0') {
                            if (inword == 1) {
                                    count++ ;
                                    inword = 0 ;
                            }
                    } else {
                            inword = 1 ;
                    }
            } while (buffer[idx++] != 0) ;
    }

    int start = 0;
    int end = 0 ;
    int curr = 0 ;
    int idx = 0 ;

    char **values = new char*[count+1];

    do {
            if (buffer[idx] == delim || buffer[idx] == '\0') {
                    end = idx;
                    if (end-start > 0) {
                            copystring(&buffer[start], &values[curr++], end - start) ;
                    }
                    start = ++end ;
            }
    } while (buffer[idx++] != 0) ;

    values[curr] = NULL ;
    for (int idx = 0; idx < count; idx++) {
            fprintf(stdout, "'%s'\n", values[idx]) ;
    }

    return values;
}

int main(int argc, char *argv[])
{
    char inputstr[] = "The, quick, brown, fox, jumped, over,,, ,,, ,,,,, ,,,, the, lazy, dog's, back" ;
    char **values = explode(inputstr, ',') ;

    while (*values != NULL) {
            fprintf(stdout, "%s\n" , *values) ;
            *values++ ;
    }

    return (0) ;
}
-1

This has probably to do with to being of type char*& instead of type char*. On the other hand, I never programmed C++ like this (are you sure that this is not C?). Using explicit memory management (like ´new´) is as good as playing playing russian roulette.

Here is a more standard C++ way of doing this:

#include <vector>
#include <string>
#include <iostream>

std::vector<std::string> splitString(std::string& str, char c) {
  std::vector<std::string> substrings;
  while(true) {
    unsigned pos = str.find(c);
    substrings.push_back(str.substr(0,pos));
    if(pos == std::string::npos) break;
    str = str.substr(pos+1);
  }
  return substrings;
}

int main()
{
  char c = '*';
  std::string str = "Some*string*that we need to split*properly*";
  std::vector<std::string> result = splitString(str,c);

  for(unsigned i = 0; i < result.size(); ++i) {
    std::cout << i << ": " << result[i] << "\n";
  }
}

Output:

0: Some
1: string 
2: that we need to split
3: properly
4:
FKaria
  • 1,012
  • 13
  • 14
  • I'm pretty much just allowed to use and , so no vectors and strings. – Fabis Apr 27 '14 at 15:35
  • go back to your teacher and say this: "sir, c++ is not c with extra bits. They are two distinct languages that happen to share some keywords and syntax rules." If you do c-style string manipulation in a c++ job you'll probably get fired. :-) – Richard Hodges Apr 27 '14 at 16:28
  • Better to understand the more basic and low level operations first, before moving on to easier, higher level operations. They don't teach this so I use char arrays when working, they teach it so I understand programming and can easily move between languages. Plus what better way to learn about pointers and memory management than with dynamic char arrays. – Fabis Apr 27 '14 at 16:44
  • Is like learnings to play the piano before playing the guitar. It can be useful, but you will be a better guitarrist if you start practicing the guitar and stop playing the piano. – FKaria Apr 27 '14 at 16:51
  • You're exaggerating, C and C++ aren't that different, at least at this level. This would actually be like learning to walk, before learning to run. – Fabis Apr 27 '14 at 16:54