динамическое выделение двойного указателя в c - PullRequest
0 голосов
/ 10 марта 2019

Этот вопрос является продолжением этого вопроса .

Вот код:

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

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    int strSize = 1;
    int i;
    int j = 0;
    int numberOfWords = 1;

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOICATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n')
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptr

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(sizeof(char*)* strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j] = &ptrChFromFile[i];
        }
        else
        {
            ptrWords[j] = 0;
            j++;
        }
    }

    for (i = 0; i < numberOfWords; i++) // free's each slot in ptrWords
    {
        free(ptrWords[i]);
    }

    free(ptrChFromFile);
    free(ptrWords);
    return 0;
}

Я пытаюсь динамически выделить мой двойной указатель на символ ptrWords.Позвольте мне объяснить мой мыслительный процесс:

ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptr

Это создает количество слотов (индексов) в ptrWords.поэтому, если у меня есть 3 слова, ptrWords должен выглядеть следующим образом:

ptrWords [индекс 0]

ptrWords [индекс 1]

ptrWords [индекс 2]

for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
{
    ptrWords[i] = malloc(sizeof(char*)* strSize);
    if (ptrWords[i] == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }
}

Этот цикл for выделяет память каждому слоту в ptrWords, равному общему количеству символов во входном файле.Так, например, если во входном файле всего 26 символов, то каждому слоту в ptrWords будет выделено 26 байтов.

ptrWords [индекс 0] имеет 26 байтов памяти

ptrWords [индекс 1] имеет 26 байтов памяти

ptrWords [индекс 2] имеет 26 байтов памяти

Я думаю, что мое выделение памяти для ptrWords правильное, но я не уверен.

for (i = 0; i < strSize; i++)
{
    if (ptrChFromFile[i] != ' ')
    {
        ptrWords[j] = &ptrChFromFile[i];
    }
    else
    {
        ptrWords[j] = 0;
        j++;
    }
}

Предполагается, что этот цикл for берет символы из ptrChFromFile и сохраняет их в ptrWords как отдельные слова.Моя логика с циклом следующая:

1) Пока ch не равен пробелу, возьмите этот символ и сохраните его в первой позиции (индекс 0) ptrWords.

2)если ch равно пробелу, поместите на его место завершающий символ ('\ 0'), затем увеличьте j на 1, чтобы перейти к следующему индексу в ptrWords, чтобы сохранить следующее слово.

Я использовал отладчик для пошагового выполнения кода, но я все еще не могу понять, в чем дело, поэтому любая помощь будет принята с благодарностью.

Спасибо


Моя реализация:

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

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    int strSize = 1;
    int i;
    int j = 0;
    int k = 0;
    int numberOfWords = 1;

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOCATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n')
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(sizeof(char*)* strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            ptrWords[j] = realloc(ptrWords[j], k+1);
            j++;
            k = 0;
        }
    }
    printf("%s", ptrWords[0]);

    free(ptrChFromFile);
    free(ptrWords);

    return 0;
}

Пример ввода: "Привет"

Вывод: Привет

¿эй


Текущая версия кода:

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


int getStrLength(char *word)
{
    int lengthOfWord = 0;
    int i;

    for (i = 0; word[i] != 0; i++)
    {
        lengthOfWord++;
    }
    return lengthOfWord;
}

int compareWords(char *firstWord, char *secondWord)
{
    while (*firstWord && *firstWord == *secondWord)
    {
        firstWord++;
        secondWord++;
    }
    return *firstWord - *secondWord;
}

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    char **ptrCrunchWord;
    int strSize = 0;
    int i;
    int j = 0;
    int k = 0;
    int numberOfWords = 0;
    int defaultWordLength = 6;

    srand(time(0)); // Use current time as seed for random generator

    ptrChFromFile = malloc(sizeof(char));

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOCATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n') // this reads in chars from file to ch variable
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+1) * sizeof(char));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }

    numberOfWords++;
    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    for (i = 0; i < strSize; i++) // This inserts words in ptrWords separated by spaces.
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            ptrWords[j] = realloc(ptrWords[j], k+1);
            j++;
            k = 0;
        }
    }
    // terminate and resize last word
    ptrWords[j][k] = 0;
    ptrWords[j] = realloc(ptrWords[j], k+1);
    j = 0;
    k = 0;

    // crunchWord code starts here:
      ptrCrunchWord = malloc(sizeof(char*));
      ptrCrunchWord[0] = malloc(strSize);

      if (ptrCrunchWord == NULL || ptrCrunchWord[0] == NULL)
       {
           puts("failed to allocate memory");
           exit(EXIT_FAILURE);
       }


    for (i = 0; i < numberOfWords; i++)
    {
        int randomIndex = rand() % numberOfWords;

    if (compareWords(ptrCrunchWord[i], ptrWords[randomIndex]) != 0) 
    {
        if (getStrLength(ptrWords[randomIndex]) >= defaultWordLength) 
        {
            ptrCrunchWord[i] = ptrWords[randomIndex]; // main problem here
        }
    }
}

    printf("The crunch word is: %s", ptrCrunchWord[0]);


    for (i = 0; i < numberOfWords; i++) // Free's allocated memory from all pointers
    {
        free(ptrWords[i]);
    }

    free(ptrChFromFile);
    free(ptrWords);
    free(ptrCrunchWord[0]);
    free(ptrCrunchWord);

    return 0;
}

Это самый последний код.Последнее, что мне нужно сделать, это сохранить все слова, которые больше или равны шести в ptrCrunchWord.Моя основная проблема заключается в выделении места в ptrCrunchWord [0] для последнего слова сокращения и сохранении слов в индексе 0. Я выделяю место только для элемента, потому что в ptrCrunchWord будет храниться только одно слово.Я написал два метода: один проверяет длину каждого слова, а другой сравнивает два слова, чтобы узнать, совпадают ли они.Наконец, мне нужно напечатать слово "хруст" без пробелов.

Спасибо

Ответы [ 2 ]

1 голос
/ 10 марта 2019

Этот цикл неправильный:

for (i = 0; i < strSize; i++)
{
    if (ptrChFromFile[i] != ' ')
    {
        ptrWords[j] = &ptrChFromFile[i];
    }
    else
    {
        ptrWords[j] = 0;
        j++;
    }
}

Вы не должны переназначать ptrWords[j], вам следует скопировать в память, выделенную в предыдущем цикле.Вам нужна другая переменная k для хранения индекса, который вы присваиваете в массиве назначения.

int k = 0;
for (i = 0; i < strSize; i++)
{
    if (ptrChFromFile[i] != ' ')
    {
        ptrWords[j][k++] = ptrChFromFile[i];
    }
    else
    {
        ptrWords[j][k] = 0;
        j++;
        k = 0;
    }
}

Вы также перешли слишком много памяти, выделенной для ptrWords.Каждое слово имеет столько символов, сколько выделено на весь размер файла.Когда вы достигнете конца каждого слова, после присвоения ptrWords[j][k] = 0 вы можете уменьшить это распределение до размера слова с помощью:

ptrWords[j] = realloc(ptrWords[j], k+1);

Другая проблема заключается в том, что вы инициализировали strSize = 1;.Это приводит к тому, что вы вводите первый символ ввода в ptrChFromFile[1] вместо ptrChFromFile[0], поэтому первое слово не копируется правильно.Он должен быть инициализирован как int strSize = 0.Но чтобы откорректировать это изменение, вам нужно увеличить все выделения ptrChFromFile на 1 символ (или сделать еще один realloc в конце, чтобы добавить место для завершающего нуля).

Когда вы выделяетепамять для ptrWords[i], вы не должны умножать на sizeof(char *).ptrWords - это массив указателей, ptrWords[i[ - это массив char.

После того, как вы закончите цикл, который считывает начальный ввод в ptrChFromFile, вам нужно увеличить numberOfWords.В противном случае вы не будете считать последнее слово перед новой строкой.

Вы не должны были удалять петлю в конце, которая освобождает все ptrWords[i].Все, что вы выделяете с помощью malloc, должно быть освобождено.

Вот рабочая версия:

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

int main(void)
{
    int ch;
    char *ptrChFromFile;
    char **ptrWords;
    int strSize = 0;
    int i;
    int j = 0;
    int k = 0;
    int numberOfWords = 1;

    ptrChFromFile = malloc(2);

    if (ptrChFromFile == NULL)
    {
        puts("COULDN'T ALLOCATE MEMORY");
        exit(EXIT_FAILURE);
    }

    while ((ch = getchar()) != '\n')
    {
        ptrChFromFile = realloc(ptrChFromFile, (strSize+2));

        if (ptrChFromFile == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }

        if (ch == ' ')
        {
            numberOfWords++;
        }

        ptrChFromFile[strSize] = ch;
        strSize++;
    }
    numberOfWords++; // increment for last word

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptrWords

    for (i = 0; i < numberOfWords; i++) // allocates number of bytes in each slot.
    {
        ptrWords[i] = malloc(strSize);
        if (ptrWords[i] == NULL)
        {
            puts("failed to allocate memory");
            exit(EXIT_FAILURE);
        }
    }

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < strSize; i++)
    {
        if (ptrChFromFile[i] != ' ')
        {
            ptrWords[j][k++] = ptrChFromFile[i];
        }
        else
        {
            ptrWords[j][k] = 0;
            ptrWords[j] = realloc(ptrWords[j], k+1);
            j++;
            k = 0;
        }
    }
    printf("%s\n", ptrWords[0]);

    for (i = 0; i < strSize; i++) {
        free(ptrWords[i]);
    }
    free(ptrChFromFile);
    free(ptrWords);

    return 0;
}
0 голосов
/ 13 марта 2019

Я постараюсь показать версию, более похожую на вашу первоначальную версию.

Я пропущу часть, читающую файл. Исправление, связанное с strSize, упомянутое Barmar, должно быть применено конечно Этот код начинается после прочтения вашего файла.

    ptrChFromFile[strSize] = 0;

    ptrWords = malloc(sizeof(char*) * numberOfWords); //creates number of slots in ptr

    if (ptrWords == NULL)
    {
        puts("failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    #define MIN_LENGTH 6
    int start = 0, end = 0;
    numWords = 0; // Start counting again. Only handle words long enough.
    for (i = 0; i < strSize; i++) // Walk the inital array again
    {
        if (ptrChFromFile[i] == ` `)
        {
          end = i;
          if (end - start >= MIN_LENGTH)
          { // Found a word? Store address and terminate.
            ptrWords = &ptrChFromFile[start];
            ptrChFromFile[i] = 0;
            numWords ++;
          }
          // Words that are too short are ignored
          // Also if a second space follows, no new word is counted...

          // Prepare for new word starting at next position.
          start = end = i+1;
        }
    }

    // Maybe one more word without a space afterwards?
    end = i;
    if (end - start >= MIN_LENGTH)
    { // Found a word? Store address and terminate.
      ptrWords = &ptrChFromFile[start];
      // ptrChFromFile[i] = 0; This word is already terminated.
      numWords ++;
    }

    ptrWords = realloc(sizeof(char*) * numberOfWords); // Reduce size to only hold long words

    // Decide number n how many words shall be concatenated
    // Use scanf or any other mechanism...
    int n = numWords / 2; 

Для выбора слов я буду использовать массив для хранения только индекса каждого слова. Инициализируется с индексом 0..n-1. Для каждого выбранного слова я перемещаю индекс в первое место в массиве и помещаю (прежний) первый элемент в выбранную позицию. После этого первые n элементов содержат случайные значения индекса. Поскольку диапазон для случайного выбора уменьшается на каждом шаге, дубликаты невозможны. Не нужно сравнивать слова.

    // Create an array to hold the indices of chosen words.
    int selectedWords[n];
    for (i = 0; i < n; i++)
      selectedWords[i] = i;

    // Select n words, store index.
    srand(time(0));
    for (i = 0; i < n; i++)
    {     
      // Pick random element 0..n
      int elem = rand()%(n-i);
      int temp;
      temp = selectedWords[i+elem];
      selectedWords[i+elem] = selectedWords[i];
      selectedWords[i] = temp;
    }
    // This first n entries hold the selected words.

    // How long will it be in the end?
    size_t len = 0;
    for (i = 0; i < n; i++)
    {
      len += strlen(ptrWords[selectedWords[n]]);     
    }

    // Get memory for final result...
    char *resultWord = malloc(len+1);
    // TODO: check for NULL
    resultWord[0] = 0;

    for (i = 0; i < n; i++)
    {
      strcat(resultWord, ptrWords[selectedWords[n]]);     
    }
    printf("%s\n", resultWord)

    free(ptrChFromFile);
    free(ptrWords);
    free(resultWord);

    return 0;
}

Код не скомпилирован и не протестирован.

...