Возникли проблемы с чтением строк из стандартного ввода

Мне нужно создать программу, которая принимает ввод со стандартного ввода в следующем формате:

abcde //number of characters in word = number of words => square shape
fghij
klmno
pqrst
uvwxy
        // \n separates first half from second
word1word //any amount of characters, any amount of words
word
word2
sdf
        // \n to end input

Мой код работает, но только в 50% случаев. У меня есть несколько примеров ввода, которые я использую для тестирования, но для некоторых из них моя функция чтения не работает.

Вот моя функция, которая читает слова. Поскольку я понятия не имею, сколько слов или какой длины они будут, я использую динамические массивы и функцию getchar().

void readWords(char **p,int *n,int w) /* before calling: n = 50; w = 20; p = 50x20 char array */
{
int i = 0,j = 0,x;
char tmp,prevtmp;

while (1)
{
    prevtmp = tmp;
    tmp = getchar();
    if ((prevtmp == '\n'  && tmp == '\n') || feof(stdin))
        break; /* no more words to read */

    if (tmp == '\n') /* end of word */
    {
        p[i][j] = '\0'; /* add \0 to create string format */

        i++;
        j = 0;
        if (i == *n) /* if there is more words than there is space for them, double the size */
            if (realloc(p,*n*2) != NULL)
                *n*=2;

        continue;
    }

    p[i][j] = tmp;
    j++;
    if (j == w) /* if width of word is larger than allocated space, double it */
    {
        for (x = 0; x < *n;x++);
            if(realloc (p[x],w*2) != NULL);

        w=w*2;
    }

}
*n = i;
}

Это пример ввода, для которого это работает (примечание: эта функция читает только вторую половину после строки только с \n):

dsjellivhsanxrr
riemjudhgdffcfz
<skipping>
atnaltapsllcelo
ryedunuhyxhedfy

atlanta
saltlakecity

<skipping 15 words>

hartford
jeffersoncity

И это ввод, который моя функция не читает правильно:

<skipping>
...oywdz.ykasm.pkfwb.zazqy...
....ynu...ftk...zlb...akn....

missouri
delaware

<skipping>

minnesota
southdakota

Что моя функция читает из этого ввода:

e
yoming
xas
florida
lvania
ana
ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ

Между этими двумя входными данными нет никакой разницы (за исключением разных слов и разного количества и длины слов), первая половина читается правильно, несмотря ни на что, но только вторая половина выдает ошибку. Как это исправить?

P.S. извините за длинный пост, если вы хотите увидеть полный ввод без пропущенных байтов, вот pastebin: http://pastebin.com/hBGn2tej


person isklenar    schedule 22.11.2012    source источник


Ответы (1)


realloc() возвращает адрес только что выделенной памяти, он не обновляет переданный в него аргумент. Так что это (и другое использование realloc()) неверно:

if (realloc(p,*n*2) != NULL)

и приведет к неправильному доступу кода к памяти, что приведет к неопределенному поведению. Сохраните результат realloc() во временную переменную и проверьте наличие не-NULL перед обновлением p. Аргумент realloc() также указывает количество байтов, а не количество элементов, поэтому вычисление аргумента размера неверно, поскольку p представляет собой массив char*, поэтому он должен быть realloc(p, sizeof(char*) * (*n * 2));. Однако изменение на p не будет видно вызывающему абоненту. Также обратите внимание, что единственными допустимыми аргументами для realloc() являются указатели, полученные из предыдущего вызова malloc(), realloc() или calloc(). Комментарий p = массив символов 50x20 в коде предполагает, что это не так.

Вот небольшой пример, который выделяет массив char*, который должен быть полезен:

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

void f(char*** p)
{
    /* Allocate space for two 'char*' elements.
       Add a NULL pointer element as sentinel value
       so caller knows where to find end of list. */
    *p = malloc(sizeof(**p) * 3);

    /* Allocate space for the two strings
       and populate. */
    (*p)[0] = malloc(10);
    (*p)[1] = malloc(10);

    strcpy((*p)[0], "hello");
    strcpy((*p)[1], "world");
    (*p)[2] = NULL;

    /* Add a third string. */
    char** tmp = realloc(*p, sizeof(**p) * 4);
    if (tmp)
    {
        *p = tmp;
        (*p)[2] = malloc(10);
        strcpy((*p)[2], "again");
        (*p)[3] = NULL;
    }
}

int main()
{
    char** word_list = 0;
    f(&word_list);

    if (word_list)
    {
        for (int i = 0; word_list[i]; i++)
        {
            printf("%s\n", word_list[i]);
            free(word_list[i]);
        }
    }
    free(word_list);

    return 0;
}

Кроме того:

  • prevtmp имеет неизвестное значение при первом использовании.
  • getchar() фактически возвращает int, а не char.
person hmjd    schedule 22.11.2012