Сбой программы - bad_alloc при создании нового массива символов

У меня есть функция С++, которая разбивает массив символов на несколько массивов символов, когда он встречает разделитель. Почему-то при сохранении третьего разбитого массива программа просто вылетает и иногда возвращает исключение std::bad_alloc.

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;
}

Трудно сказать, потому что на самом деле это не говорит мне, на какой строке что-то идет не так, но я думаю, что это происходит на

to = new char[garums];

Я пытался отладить эту строку в CodeBlocks, но по какой-то причине при использовании точек останова и отслеживании переменных приложения работают нормально и выполняются правильно. Вылетает только при нормальной работе, без отладки...

Также обратите внимание, что я не могу использовать строки или любую другую библиотеку, кроме fstream и iostream.

РЕДАКТИРОВАТЬ: я попытался изменить часть new char[garums] на new char[100], и она волшебным образом заработала. Проблема в том, что я тогда изменил его на new char[10], и в этом случае все еще работало. Я даже вывел сохраненный текст в консоль, и она все правильно сохранила. Как он мог сохранить большие слова в массиве символов длиной 10 символов (слова, которые я тестирую, длиннее 10 символов)? Когда я изменил его на new char[1], он снова начал падать, но снова только после 3-й итерации цикла. Таким образом, он каким-то образом сохранил первые 2 слова в массиве длиной в 1 символ?

EDIT2: И теперь он волшебным образом начал работать даже с new char[garums]. Что-то здесь действительно не так, у кого-нибудь есть идеи?


person Fabis    schedule 27.04.2014    source источник
comment
вы можете выполнить выполнение, отслеживая свой garums перед каждым new char[garums]   -  person gha.st    schedule 27.04.2014
comment
Я думаю, у вас неправильное представление о том, что вы хотите сделать. Вы получаете одномерный массив. И ваш результат, как мне кажется, должен быть двумерным массивом. Ваш результат должен быть массивом массивов символов. Если бы я был вами, я бы 1) перебрал входную строку и сохранил количество и позицию каждого разделителя, чтобы 2) скопировать подстроки в двумерный массив результатов.   -  person Stefan Falk    schedule 27.04.2014
comment
Да, это 2D-массив, потому что он разбивает 1D-массив на несколько 1D-массивов — 2D-массив. Кроме того, это в значительной степени то, что делает функция, просто по какой-то причине она падает при попытке инициализировать массивы.   -  person Fabis    schedule 27.04.2014


Ответы (3)


Ошибка, на которую вы ссылаетесь в своем вопросе, вероятно, возникает при попытке использовать указатель на указатель, возвращаемый функцией взрыва. Некоторые указатели; Если вам нужно написать код C, не используйте мешанину из C/C++. Используйте библиотечные функции, а не заново изобретайте колесо (strncpy в copystring). Счетчик слов был выключен, потому что вы не приняли во внимание слово. между последним разделителем и EOL Ниже приведены некоторые незначительные изменения в вашем коде в качестве полного примера:

#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) ;
}
person arnoux123    schedule 27.04.2014

Поскольку я не знаю, какие у вас есть входные данные, мне придется угадать:

Здесь вы выделяете свой массив указателей, но обратите внимание, что все указатели не инициализированы.

strings = new char*[count]

затем, когда вы анализируете код, вы используете переменную curr, которой вы позволяете свободно работать, поэтому нет уверенности, что все strings[] были установлены на какое-то значение или curr попадает на число больше, чем count.

На вашем месте я бы поставил чек, чтобы убедиться, что:

а) curr не превышает count

б) что, если curr достигает значения меньше count, установить остальные указатели на nullptr

person AndersK    schedule 27.04.2014

Вероятно, это связано с тем, что to относится к типу char*&, а не к типу char*. С другой стороны, я никогда так не программировал на C++ (вы уверены, что это не C?). Использование явного управления памятью (например, «новое») так же хорошо, как играть в русскую рулетку.

Вот более стандартный способ C++ сделать это:

#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";
  }
}

Вывод:

0: Some
1: string 
2: that we need to split
3: properly
4:
person FKaria    schedule 27.04.2014
comment
Мне просто разрешено использовать «iostream» и «fstream», поэтому никаких векторов и строк. - person Fabis; 27.04.2014
comment
вернитесь к своему учителю и скажите: сэр, С++ — это не С с дополнительными битами. Это два разных языка, которые имеют общие ключевые слова и правила синтаксиса. Если вы выполняете манипуляции со строками в стиле C в задании на C++, вас, вероятно, уволят. :-) - person Richard Hodges; 27.04.2014
comment
Лучше сначала понять более простые и низкоуровневые операции, прежде чем переходить к более простым операциям более высокого уровня. Они не учат этому, поэтому я использую массивы символов при работе, они учат этому, поэтому я понимаю программирование и могу легко переключаться между языками. Кроме того, какой лучший способ узнать об указателях и управлении памятью, чем с динамическими массивами символов. - person Fabis; 27.04.2014
comment
Это как научиться играть на пианино, прежде чем играть на гитаре. Это может быть полезно, но вы станете лучшим гитаристом, если начнете заниматься на гитаре и перестанете играть на фортепиано. - person FKaria; 27.04.2014
comment
Вы преувеличиваете, C и C++ не так уж отличаются, по крайней мере, на этом уровне. На самом деле это было бы похоже на то, чтобы научиться ходить, прежде чем научиться бегать. - person Fabis; 27.04.2014