Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > Работа с malloc() и указателями в СИ


Автор: murtukov 30.1.2013, 07:32
Всем привет.

Написал программу, которая выделяет память под двумерный массив и сохраняет в него имена. Размер выделяемой памяти зависит от количества и длины слов, которое определяется пользователем. Программка рассчитана на сохранение n-го количества слов, которое также определяется пользователем в начале программы (при запуске).

Вот, собственно, и сам код программы:

Код

#include <stdio.h>
#include <string.h>
 
// функция выделения памяти для одного слова. На входе m - количество букв, определенное с помощью strlen(). *mass - указатель на указатель
void memory_for_string(char *mass, int m)
{
    *mass = (char *)malloc((m+1)*sizeof(char)); // прибавляем к переменной 'm' 1 для выделения места под знак конца строки
}
 
int main(void)
{
    int m=0, n=0, i=0;
    char **mass, str[20];   // **mass - указатель на указатель. str - временный массив для определения длины введенного слова
 
    puts("Please, enter a number of strings");  // пожалуйста, введите число строк
    scanf("%d", &n);
    fflush(stdin);  // очищаем стандартный поток после scanf()
 
    mass = (char *)malloc(n*sizeof(char *));  // выделяется память под массив указателей, адрес первой ячейки сохраняется в mass
 
    while(i<n)  // выполнять, пока не введено n-е количество имен
    {
        printf("Please, enter the name %d: ", i+1);  // пожалуйста, введите i-е имя
        gets(str);  // сохраняем введенное слово
        m = strlen(str);  // определяем длину слова и сохраняем в m
        memory_for_string(mass+i, m);  // запускаем функцию для выделения памяти под длину слова
        strcpy(*(mass+i), str);  // копируем слово в выделенную память
        i++;
    }
 
    i=0;
    while(i<n)
        {
          printf("\nThe name %d is: %s", i+1, *(mass+i));
          i++;
        }
    return 0;
}


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

Спасибо.

Автор: feodorv 30.1.2013, 08:52
Код как следует не смотрел, но сразу бросилось в глаза:
Цитата(murtukov @  30.1.2013,  08:32 Найти цитируемый пост)
void memory_for_string(char *mass, int m)
{
    *mass = (char *)malloc((m+1)*sizeof(char)); // прибавляем к переменной 'm' 1 для выделения места под знак конца строки
}

Здесь mass - указатель на char, а не char*, в результате *mass присваивает один char... Правильно:
Код

void memory_for_string(char **mass, int m)...


Добавлено через 4 минуты и 21 секунду
Вообще в таких ситуациях лучше возвращать указатель на заказанную память:
Код

char *memory_for_string( int m ) ...

А ещё лучше сразу же в подпрограмме определять длину копируемой строки, а потом её ещё и скопировать в заказанную память. Получится strdup smile

Добавлено через 11 минут и 2 секунды
Ещё замечание по стилю программирования. Если mass - это массив строк, то лучше к такому массиву обращаться как
Код

memory_for_string(&mass[i], m);



Автор: fish9370 31.1.2013, 13:02
feodorv все грамотно расписал, я лишь добавлю:

- функция malloc может не выделить память (смотри man malloc), при этом следует корректно обработать данную ситуацию. Обычно пишут обертку типа:

Код

inline void * x_malloc(size_t len)
{
        void *p;

        if (!(p = malloc(len)))
                MALLOC_FAILURE_MSG; /* сообщение об ошибке */

        return p;
}


- функция malloc не инициализирует память нулями, если нужно чтобы память была очищена используй calloc (это может быть более быстро, чем очищать самому, так как ядро постарается предоставить буфер уже чистый)

- функцию malloc в Си не обязательно (и не желательно) приводить к типу (смотри пример выше)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)