realloc(): недопустимая ошибка следующего размера при перераспределении памяти для массива строк

#arrays #c #pointers

Вопрос:

Я просматривал Начало C, Пятое издание, и в настоящее время я нахожусь в главе 7, которая посвящена указателям. Я попытался запустить пример, который был приведен в этой главе, но я сталкиваюсь с realloc(): invalid next size ошибкой, когда массив выходит за пределы 6 элементов. Вот код, который в основном скопирован и вставлен из книги:

 // Program 7.14 Using array notation with pointers to sort strings

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

#define BUF_LEN 100                                // Length of input buffer
#define COUNT         5                            // Initial number of strings

int main(void)
{
  char buf[BUF_LEN];                               // Input buffer
  size_t str_count = 0;                            // Current string count
  size_t capacity = COUNT;                         // Current maximum number of strings
  char **pS = calloc(capacity, sizeof(char*));     // Pointers to strings
  char** psTemp = NULL;                            // Temporary pointer to pointer to char
  char* pTemp = NULL;                              // Temporary pointer to char
  size_t str_len = 0;                              // Length of a string
  bool sorted = false;                             // Indicated when strings are sorted
  printf("Enter strings to be sorted, one per line. Press Enter to end:n");

  // Read in all the strings
  char *ptr = NULL;
  while(true)
  {
    ptr = fgets(buf, BUF_LEN, stdin);
    if(!ptr) // Check for read error
    {
      printf("Error reading string.n");
      free(pS);
      pS = NULL;
      return 1;
    }

    if(*ptr == 'n') break;             // Empty line check

    if(str_count == capacity)
    {
      capacity  = capacity/4;           // Increase capacity by 25%

      if(!(psTemp = realloc(pS, capacity))) return 1;

      pS = psTemp;
    }
    str_len = strnlen(buf, BUF_LEN)   1;
    if(!(pS[str_count] = malloc(str_len))) return 2;
    strcpy(pS[str_count  ], buf);
  }

  // Sort the strings in ascending order
  while(!sorted)
  {
    sorted = true;
    for(size_t i = 0 ; i < str_count - 1 ;   i)
    {
      if(strcmp(pS[i], pS[i   1]) > 0)
      {
        sorted = false;                 // We were out of order so. . .
        pTemp= pS[i];                   // swap pointers pS[i]. . .
        pS[i] = pS[i   1];              // and. . .
        pS[i   1] = pTemp;              // pS[i   1]
      }
    }
  }

  // Output the sorted strings
  printf("Your input sorted in ascending sequence is:nn");
  for(size_t i = 0 ; i < str_count ;   i)
  {
    printf("%s", pS[i]);
    free(pS[i]);                        // Release memory for the word
    pS[i] = NULL;                       // Reset the pointer
  }
  free(pS);                             // Release the memory for pointers
  pS = NULL;                            // Reset the pointer
  return 0;
}
 

Ошибка возникает в этой строке:

 if(!(psTemp = realloc(pS, capacity))) return 1;
 

Кроме того, я говорю, что код «в основном» скопирован, потому что код из книги использует функции C11, такие как strnlen_s и strcpy_s к которым у меня нет доступа. Я использую strnlen и strcpy вместо этого. Я не уверен, что это то, что вызывает проблему. Однако вот дословный код из книги:

 // Program 7.14 Using array notation with pointers to sort strings
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>

#define BUF_LEN 100                                // Length of input buffer
#define COUNT         5                            // Initial number of strings

int main(void)
{
  char buf[BUF_LEN];                               // Input buffer
  size_t str_count = 0;                            // Current string count
  size_t capacity = COUNT;                         // Current maximum number of strings
  char **pS = calloc(capacity, sizeof(char*));     // Pointers to strings
  char** psTemp = NULL;                            // Temporary pointer to pointer to char
  char* pTemp = NULL;                              // Temporary pointer to char
  size_t str_len = 0;                              // Length of a string
  bool sorted = false;                             // Indicated when strings are sorted
  printf("Enter strings to be sorted, one per line. Press Enter to end:n");

  // Read in all the strings
  char *ptr = NULL;
  while(true)
  {
    ptr = fgets(buf, BUF_LEN, stdin);
    if(!ptr) // Check for read error
    {
      printf("Error reading string.n");
      free(pS);
      pS = NULL;
      return 1;
    }

    if(*ptr == 'n') break;             // Empty line check

    if(str_count == capacity)
    {
      capacity  = capacity/4;           // Increase capacity by 25%

      if(!(psTemp = realloc(pS, capacity))) return 1;

      pS = psTemp;
    }
    str_len = strnlen_s(buf, BUF_LEN)   1;
    if(!(pS[str_count] = malloc(str_len))) return 2;
    strcpy_s(pS[str_count  ], str_len, buf);
  }

  // Sort the strings in ascending order
  while(!sorted)
  {
    sorted = true;
    for(size_t i = 0 ; i < str_count - 1 ;   i)
    {
      if(strcmp(pS[i], pS[i   1]) > 0)
      {
        sorted = false;                 // We were out of order so. . .
        pTemp= pS[i];                   // swap pointers pS[i]. . .
        pS[i] = pS[i   1];              // and. . .
        pS[i   1] = pTemp;              // pS[i   1]
      }
    }
  }

  // Output the sorted strings
  printf("Your input sorted in ascending sequence is:nn");
  for(size_t i = 0 ; i < str_count ;   i)
  {
    printf("%s", pS[i]);
    free(pS[i]);                        // Release memory for the word
    pS[i] = NULL;                       // Reset the pointer
  }
  free(pS);                             // Release the memory for pointers
  pS = NULL;                            // Reset the pointer
  return 0;
}
 

Я просмотрел множество сообщений о StackOverflow и других местах, которые помогли мне понять, что происходит не так, но я не смог этого понять. Я также использовал gdb и valgrind, чтобы попытаться диагностировать проблему, но я также не смог извлечь много информации из этих инструментов. Хотя я довольно неопытен в них, особенно в вальгринде.

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

 Enter strings to be sorted, one per line. Press Enter to end:
Many a mickle makes a muckle.
A fool and your money are soon partners.
Every dog has his day.
Do unto others before they do it to you.
A nod is as good as a wink to a blind horse.
The bigger they are, the harder they hit.
Least said, soonest mended.
realloc(): invalid next size
signal: aborted (core dumped)
 

Независимо от того, какой ввод, я получаю эту ошибку после 7 строк.

Любая помощь в этом будет весьма признательна. Заранее спасибо!

Комментарии:

1. Подобная ошибка обычно возникает, когда вы выходите за пределы выделенной памяти перед вызовом realloc . Например, если вы выделяете мало памяти, что вы делаете в realloc вызовах (размер для перераспределения-это количество выделяемых байтов , а не количество «элементов»).

2. Я почти уверен, что вы не скопировали пример дословно. Ты должен сделать это первым. Почему у вас нет доступа к функциям C11? Что мешает вам использовать не древний компилятор, совместимый с C11?

3. Спасибо всем за комментарии, решение @user3121023 устранило проблему для меня. Должен ли я ответить на свой собственный вопрос решением?

4. @SergeyA Я использую онлайн-компилятор на Replit для запуска кода, и я предполагаю, что у компилятора там нет функций C11. Я также отредактировал вопрос, включив в него код, взятый дословно из книги.

5. @amehdi96 вы можете использовать любой другой онлайн-компилятор, который поддерживает C11, например coliru.stacked-crooked.com

Ответ №1:

Благодаря предложению пользователя 3121023 я решил эту проблему, изменив эту строку:

 if(!(psTemp = realloc(pS, capacity))) return 1;
 

к этому:

 if(!(psTemp = realloc(pS, capacity * sizeof(*pS)))) return 1;
 

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