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

Я пытаюсь создать простое приложение на C, которое будет читать строки из файла, аналогично тому, как я это сделал на C#. Однако я столкнулся с проблемой: когда цикл for выполняется повторно, память для **ptext не выделяется, и я не знаю, как это исправить. Кроме того, количество символов в выделенной памяти почему-то не равно 2 байтам, а может варьироваться. Я не понимаю, почему использование функции *alloc ведет к таким странным результатам. Я проводил проверки на NULL (которые не срабатывали, и я вернул всё как было), и не думаю, что на моем ПК не хватает 3 байтов. 

Вот часть кода, с которой я работаю:
<pre><code class="c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

#define _CRT_SECURE_NO_WARNINGS

FILE* create_filestream(const char* filepath, char* buffer);
int read_text_in_file(FILE* filestream, char*** ptext, size_t* text_size);

int main() {
	char buffer[32];
	FILE* f = create_filestream("map.txt", &amp;buffer);

	char **text;
	size_t text_size = NULL;

	read_text_in_file(f, &amp;text, &amp;text_size);
}
  
int read_text_in_file(FILE* filestream, char*** ptext, size_t* text_size){
	char buffer[32],* data = NULL;

	size_t bytes_read, nums = 0, j = 0;
	*text_size = 0;
	
	*ptext = malloc(sizeof(char**));
	**ptext = malloc(sizeof(char*));

	while (!feof(filestream)) {
		bytes_read = fread(&amp;buffer, sizeof(char), sizeof(buffer), filestream);
		
		if (ferror(filestream) || bytes_read == 0) return -1;

		for (size_t i = 0; i &lt; bytes_read; i++) {
			if (buffer[i] == '\0') {
				nums++;
				j = 0;
				if(*ptext = (char**)realloc(*ptext, sizeof(*ptext) + sizeof(char**)))
					return -2;
				continue;
			}

			(*text_size)++;
			
			data = reallo

Пожалуйста, объясните, что я делаю неправильно и как можно устранить эти проблемы.
  • 20 марта 2025 г. 15:15
Ответы на вопрос 2
Проблемы, с которыми вы столкнулись, касаются нескольких аспектов управления динамической памятью в языке C. Давайте разберем ваш код и выделим проблемы и места для улучшения.

1. **Неинициализированные указатели**: Переменная `text_size` должна быть типа `size_t`, но вы инициализируете её как `NULL`. Следует использовать правильное значение, например `0`, вместо `NULL` для переменной, которая предназначена для увеличения счётчика.

   ```c
   size_t text_size = 0; // Исправлено
   ```

2. **Выделение памяти**: В строке `*ptext = malloc(sizeof(char**));` вы выделяете память для указателя на указатели. Это не совсем корректно, так как стоит выделять по количеству строк, а не по количеству указателей. Также стоит учесть, что вы хотите выделить память для множества строк. Исходный фрагмент кода выделяет память для одного указателя.

3. **Функция `realloc`**: Вы используете `realloc` неправильно. Вместо проверок на успех выделения памяти, вы просто возвращаете -2 в случае успеха. Правильный синтаксис должен быть таким: 
   ```c
   char **temp = realloc(*ptext, (nums + 1) * sizeof(char*));
   if (temp == NULL) {
       // Обработка ошибки, memory allocation failed
       return -2;
   }
   *ptext = temp;
   ```

4. **Чтение данных из файла**: При использовании `fread` вы передаете `&buffer`, что неправильно. Вам нужно передать `buffer` без амперсанда, поскольку `buffer` уже является указателем на его первый элемент. 

5. **Обработка строки**: У вас не хватает логики для создания и сохранения строк в динамически выделенной памяти. В частности, строки нужно копировать в `*ptext`.

6. **Проблема с передачей аргументов**: Вы неправильно передаете указатель на `ptext` и `text_size` в функции. Вместо `&text` используйте `ptext`, чтобы указывать на указатель, в который будет записываться адрес динамически выделенной памяти.

Вот скорректированная версия вашей функции `read_text_in_file`:

```c
int read_text_in_file(FILE* filestream, char*** ptext, size_t* text_size) {
    char buffer[32];
    char* data = NULL;

    size_t bytes_read, nums = 0;
    *text_size = 0;
    
    *ptext = NULL; // Инициализация указателя на указатели

    while (!feof(filestream)) {
        bytes_read = fread(buffer, sizeof(char), sizeof(buffer) - 1, filestream);
        buffer[bytes_read] = '\0'; // Обеспечить завершение строки

        if (ferror(filestream) || bytes_read == 0) return -1;

        for (size_t i = 0; i < bytes_read; i++) {
            if (buffer[i] == '\n') { // Используем '\n' для разделения строк
                nums++;
                *text_size += 1;
                char** temp = realloc(*ptext, nums * sizeof(char*));
                
                if (temp == NULL) {
                    // Обработка ошибки
                    return -2;
                }
                *ptext = temp;

                (*ptext)[nums - 1] = strndup(buffer, i); // Копируем строку
                buffer[0] = '\0'; // Очищаем буфер
                break;
            }
        }
    }
    return 0; // Успех
}
```

Обратите внимание на:
- Я заменил условие для разделения строк на `'\n'`.
- Добавил функцию `strndup()` для дублирования строки. Не забудьте включить `<string.h>`, если вы будете использовать `strdup()`, и очистить память для каждой строки, когда они больше не нужны.

Эти изменения должны помочь вам устранить проблемы с памятью и обеспечить правильную обработку строк, извлекаемых из файла.
Ваш вопрос не по C++, а по C, это разные языки. 

sizeof(buffer) в функции create_filestream() вернёт размер указателя (4 или 8 байт), а не размер буфера buffer из функции main, т. к. функция create_filestream про него ничего не знает. Скорее всего, это не то, чего Вы хотите.

Строка "if(*ptext = (char**)realloc(*ptext, sizeof(*ptext) + sizeof(char**)))", по-видимому, должна к текущему размеру данных, ассоциированных с *ptext, добавлять размер ещё одного указателя. По факту sizeof(*ptext) - это размер char**, т. е. размер указателя, т. е. у Вас всегда будет здесь или 8 байт (сумма размеров двух указателей на 32-битной платформе), или 16 (на 64-битной). Получить размер массива, который в данный момент ассоциирован с указателем, оператором sizeof() нельзя и в общем случае вообще нельзя, его нужно хранить отдельно.

Перечитайте внимательно главу про обращение с указателями. Пока у Вас каша, которая вряд ли будет работать ожидаемым образом. Нужно чётко понимать, что такое char*, char**, char***, sizeof(ptext), sizeof(*ptext) и т. д.
Похожие вопросы