Использование строк и Malloc/Realloc

Скажу честно, я полный новичок в c. Таким образом, такие вещи, как malloc и realloc, являются чуждыми понятиями. Я думаю, что у меня есть основы, но я просто не могу понять это на 100%.

while (int args = scanf("%s", string)) {
    if (args < 0) break;
    count++;

    if (array == NULL) {
        array = (char *) malloc(strlen(string));

        if (array == NULL) {
            printf("Error allocating memory");
            exit(1);
        }
    } else {
        printf("%s %d\n", string, strlen(string));
        array = (char *) realloc(array, (sizeof(array) + strlen(string) + 1));

        if (array == NULL) {
            printf("Error allocating memory");
            free(array);
            exit(1);
        }

        printf("%lu\n", sizeof(array));
    }

    strcpy(&array[count - 1], string);
}

Чтение из терминала - файл cat | ./program и представляет собой просто набор слов произвольной длины. Я пытаюсь собрать их всех в массив (массив).

Редактировать: я должен упомянуть, что я, по-видимому, пытаюсь получить доступ к памяти, которую я не выделил: malloc: *** error for object 0x7fe9e04039a0: incorrect checksum for freed object - object was probably modified after being freed. *** set a breakpoint in malloc_error_break to debug Segmentation fault: 11


person Tyler Sebastian    schedule 24.09.2013    source источник
comment
while (int args = scanf("%s", string)) действительно ли это компилируется в вашей системе?   -  person ouah    schedule 25.09.2013
comment
да как посоветуете сделать?   -  person Tyler Sebastian    schedule 25.09.2013
comment
Я бы сначала рекомендовал использовать компилятор C для компиляции C, вы, вероятно, используете компилятор C++.   -  person ouah    schedule 25.09.2013
comment
спасибо, исправил его для работы с gcc вместо g++ - я даже не знал, что мой редактор использует его.   -  person Tyler Sebastian    schedule 25.09.2013
comment
Показ объявлений string и array поможет... это (array = (char *) malloc(strlen(string));), вероятно, неверно; скорее всего, это должен быть array = malloc(sizeof(*array));, что избавляет меня от необходимости знать тип array и все же дает правильный ответ. Если вы действительно выделяете char *, то вам почти наверняка понадобится strlen(string)+1, чтобы разрешить нулевой завершающий байт. Ваш код не выглядит полностью последовательным. Если вам нужен массив строк, вам нужен как массив указателей на символы, так и указатели на каждую строку: char **array = 0; но…   -  person Jonathan Leffler    schedule 25.09.2013
comment
символ * массив; На самом деле я ничего не инициализирую до блока if (array == null). и спасибо за указание на нулевой терминатор - это была ошибка с моей стороны.   -  person Tyler Sebastian    schedule 25.09.2013


Ответы (2)


Похоже, вы не понимаете, что такое указатели, строки и символы в C. Например, вот описание.

Вот основные проблемы:

  1. char* не является строковым типом. Это указатель на место в памяти, где строковые данные лежат посимвольно и заканчиваются символом '\0' (нулевой терминатор).
  2. Таким образом, strcpy просто копирует набор символов из одного места (строковая переменная) в другое. В вашем случае он копирует их в массив, начиная с элемента count-1. Итак, если вы прочитали строку длиннее 1 символа, вы потеряли данные. Что вы, вероятно, захотите сделать, так это суммировать длины всех предыдущих строк и написать, начиная с этого места.
  3. Оставшаяся проблема является следствием: вы не выделяете место для нулевого терминатора во время первой итерации (что приводит к тому, что strcpy обращается к нераспределенной памяти и, вероятно, приводит к сообщению, которое вы видите после завершения программы).
person yeputons    schedule 24.09.2013
comment
На самом деле, в C нет строкового типа, который вы можете свободно выделять, объединять и делать разные вещи, как вы делаете со String в Java или str в Python. Строки здесь представляют собой массивы символов, и все, что вы можете сделать, ограничено стандартными библиотечными функциями и арифметикой указателей. - person yeputons; 25.09.2013
comment
чтобы суммировать длины всех предыдущих строк, это что-то вроде for (i = 0; i < count - 1; i++) len = strlen(array[i]), а затем писать в этом месте, это strcpy(&array + len, string) - person Tyler Sebastian; 25.09.2013
comment
Неа. char* — это массив символов. Если вы хотите записать в него несколько строк, вы можете сделать это, только прочитав их один к одному, разбив их, например, по нулевым символам. Вот так: строка\0other\0onemore\0. А начала строк будут на массиве[0], массиве[len1+1] и так далее. - person yeputons; 25.09.2013
comment
Но есть еще один способ: создать массив char*. Это будет иметь тип 'char**' (указатель на указатель на char). После этого вы добавляете один элемент в этот массив на каждой итерации. Также вы выделяете дополнительный массив для этой конкретной строки на каждой итерации, состоящий из символов strlen+1. Затем вы копируете данные из своего буфера в последний массив и, наконец, сохраняете его адрес в свой первый массив, в котором хранятся указатели на все прочитанные вами строки. - person yeputons; 25.09.2013
comment
В C есть строки, хотя и не строкового типа. В C: string — это непрерывная последовательность символов, заканчивающаяся первым нулевым символом и включающая его. В C есть указатели на строку. Указатель на строку — это указатель на ее начальный символ (самый низкий адрес). С11 7.1.1 1 - person chux - Reinstate Monica; 25.09.2013
comment
@yeputons спасибо, этот ответ помог мне больше всего на свете. В итоге я переоценил и пошел с массивом char **. Еще раз спасибо. - person Tyler Sebastian; 25.09.2013

Чтобы упростить процесс, я выбрал char ** array вместо char * array. Для каждой итерации моего цикла while (который, кстати, теперь while (scanf("%s", string) > 0) соответствует стандартам gcc (первоначально я компилировал с помощью g++)), я realloc использую count x sizeof(char *), а затем я могу array[count - 1] = (char *) malloc(sizeof(string + 1) наконец, strcpy(array[count - 1], string)

person Tyler Sebastian    schedule 24.09.2013