Форум программистов, компьютерный форум, киберфорум
C для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.67/9: Рейтинг темы: голосов - 9, средняя оценка - 4.67
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99
1

Работа с malloc - найти ошибку в коде

30.01.2013, 08:17. Показов 1820. Ответов 11
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Всем привет.

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

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

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#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(). Прошу помочь найти ошибку в коде.

Спасибо.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.01.2013, 08:17
Ответы с готовыми решениями:

Работа с файлами (найти ошибку в коде)
Здравствуйте, столкнулся с такой проблемой. Написал программу, без считывания и вывода в файл она...

Работа со списками: найти ошибку в коде
Добрый день! Коллеги, нужна помощь, буду очень благодарен. Дали такое задание: 1. Какая проблема...

Работа с файлами в Си, не могу найти ошибку в коде
Язык: &quot;Си&quot; Задача: &quot;Создать файл, содержаший сведения о месячной зарплате N рабочих завода. В...

Работа цикла типа while. Найти ошибку в коде
Добрый день. Ребята, помогите, пожалуйста. Не могу понять, что не так. В итоге результат выходит:...

11
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12460 / 7484 / 1754
Регистрация: 25.07.2009
Сообщений: 13,763
30.01.2013, 09:56 2
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

murtukov, а при компиляции предупреждения читать не нужно? Функция ваша принимает указатель на символ, выделяет память под строку и указатель на эту память пытается тому самому символу присвоить. Внутри main тоже не комильфо. Посмотрите, как у Вас переменная mass определена, и как под неё память выделяется, найдите странность... Ну и куда строки копируются, присмотритесь внимательнее.

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*...*/
int numRows, i;
char buf[BUFSIZ], ** strings;
/* поучить количество строк */
strings = (char**)malloc(sizeof(char*) * numRows); 
// на самом деле в С приводить к какому-то типу то, что возвращает malloc
// не нужно и даже вредно, но компилировать будете наверняка, как С++
// и получите ошибку при компиляции
if ( ! strings ) {
    // ошибка выдиления памяти
}
for ( i = 0; i < numRows; ++i ) {
    if ( ! fgets(buf, BUFSIZ, stdin) ) {
        // ошибка ввода
    }
    if ( ! ( strings[i] = (char*)malloc(strlen(buf) + 1) ) ) {
        // ошибка выделения памяти
    }
    strcpy(strings[i], buf);
}
 
//что-то с этими строками сделать
 
for ( i = 0; i < numRows; ++i )
    free(strings[i]);
free(strings);
/*...*/
0
Диссидент
Эксперт C
27706 / 17322 / 3812
Регистрация: 24.12.2010
Сообщений: 38,979
30.01.2013, 11:50 3
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
char *memory_for_string(int m)
{
    char *mass = (char *)malloc((m+1)*sizeof(char)); 
    return mass;
}
 
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
        mass[i] = memory_for_string( m);  // запускаем функцию для выделения памяти под длину слова
        strcpy(*(mass+i), str);  // можно и strcpy(mass[i], str);
        i++;
    }
  .....
2
10 / 10 / 5
Регистрация: 30.01.2013
Сообщений: 99
30.01.2013, 21:33  [ТС] 4
Байт, спасибо за рабочий вариант кода.

Вот только вопрос: Почему мой код не работает даже после поправки?

Было так: mass = (char *)malloc(n*sizeof(char *));
Исправил: mass = (char **)malloc(n*sizeof(char *));

И все равно не работает. Ясно, что дело в кривонаписанной функции, но в чем конкретно?
Могли бы вы мне объяснить, что именно происходит в моей функции?

Спасибо.

Добавлено через 49 минут
А, все, разобрался.

easybudda,
Код у меня не такой уж и кривой, нужно было всего лишь звездочку вставить в двух местах, а именно:

тут - void memory_for_string(char **mass, int m)
и тут - mass = (char **)malloc(n*sizeof(char *));

И все работает. Зачем нужно было писать целый новый код с новыми названиями переменных?

Цитата Сообщение от easybudda Посмотреть сообщение
// на самом деле в С приводить к какому-то типу то, что возвращает malloc // не нужно и даже вредно
- Что вредного в явном приведении типа, что возвращает malloc? Как раз таки наоборот - без его указания код может и вовсе не скомпилироваться, так как malloc возвращает void по умолчанию и не все компиляторы делают конвертирование типа. Встречался с подобным.

Цитата Сообщение от easybudda Посмотреть сообщение
Ну и куда строки копируются, присмотритесь внимательнее.
- Все у меня правильно там копируется


Спасибо всем, вопросов больше нет, тема закрыта.
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.01.2013, 21:40 5
easybudda, без приведения malloc возвращает void *

Добавлено через 1 минуту
ТС, столько malloc-ов и ни одного free..
0
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12460 / 7484 / 1754
Регистрация: 25.07.2009
Сообщений: 13,763
30.01.2013, 23:19 6
Цитата Сообщение от MrGluck Посмотреть сообщение
без приведения malloc возвращает void *
Да ну?!

Цитата Сообщение от murtukov Посмотреть сообщение
malloc возвращает void по умолчанию и не все компиляторы делают конвертирование типа.
Все С компиляторы приводят void * к нужному типу автоматически, все С++ компиляторы этого принципиально не делают. Не компилируйте код С, как С++, и будет Вам счастье. Как и чем в вашей IDE компилируются программы - ищите в настройках IDE.

Цитата Сообщение от murtukov Посмотреть сообщение
Что вредного в явном приведении типа, что возвращает malloc?
Может привести к трудноуловимой ошибке. Подробности - Роберт Лав "LINUX системное программирование", глава 8, раздел "Выделение динамической памяти".
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.01.2013, 23:45 7
Цитата Сообщение от easybudda Посмотреть сообщение
Все С компиляторы приводят void * к нужному типу автоматически, все С++ компиляторы этого принципиально не делают.
ну тогда мб все же приводить для капабилити
0
Эксперт С++
5056 / 3116 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
31.01.2013, 13:53 8
Цитата Сообщение от MrGluck Посмотреть сообщение
ну тогда мб все же приводить для капабилити
Лучше не стоит. Компилятор в 100% случаев приведёт void * к правильному типу, а вот программист...
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
31.01.2013, 22:34 9
silent_1991, С++ компилятор не приведет, в том то и дело, ну а программист должен быть совсем ту-ту, чтобы ошибиться в типе, указанном в начале строки.
Хотя дело спорное.

Не по теме:

Спасибо за книжку, почитаем-с)
если на читалку есть готовый формат (не дежавюшка) скиньте в лс, спасибо

0
Эксперт С++
5056 / 3116 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
01.02.2013, 10:12 10
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

Цитата Сообщение от MrGluck Посмотреть сообщение
С++ компилятор не приведет
Ну так а речь-то именно о С. Вообще, есть хороший пример, как раз с маллоком, которого я придерживаюсь:
C
1
2
type *ptr = NULL;
ptr = malloc(size * sizeof(*ptr));
Если угораздить изменить тип type на другой, то в этом случае достаточно изменить его только в объявлении. В классическом же варианте:
C
1
type *ptr = (type *)malloc(size * sizeof(type));
аж в трёх местах. И если заработался, и к концу рабочего дня не изменишь тип в sizeof, например, получишь бааальшую головную боль при отладке. Я уж не говорю о случае с указателем двойным, тройным и т.д. Там вообще легче лёгкого в звёздочках запутаться.
1
Модератор
Эксперт PythonЭксперт JavaЭксперт CЭксперт С++
12460 / 7484 / 1754
Регистрация: 25.07.2009
Сообщений: 13,763
01.02.2013, 10:38 11
Лучший ответ Сообщение было отмечено Памирыч как решение

Решение

silent_1991, есть ещё "классический" подход - объявлять по своему типу для всего подряд:
C
1
2
3
typedef int shoesize_t;
/*...*/
shoesize_t * arr = malloc(sizeof(shoesize_t) * NUMBER_OF_SHOES);
Если вдруг окажется, что прога для тру-элитного салона обуви, и клиентам пятки штангенциркулем с точностью до десятой доли миллиметра измеряют, достаточно будет объявление типа изменить
C
1
typedef double shoesize_t;
2
Эксперт С++
5056 / 3116 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
01.02.2013, 12:27 12
easybudda, согласен, тоже вариант.
0
01.02.2013, 12:27
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
01.02.2013, 12:27
Помогаю со студенческими работами здесь

Найти и исправить ошибку в коде (работа с указателями)
Здравствуйте! Есть такой вопрос по этому коду: void fun(char *buff) { char *word = new char;...

Работа с файлами: запись, добавление, чтение (найти ошибку в коде)
Надо создать программу для работы с файлами. Вводим значения: 1: запись 2:добавление 3:чтение ...

Двумерный массив. Поиск нулей.Не могу найти ошибку ошибку в коде
Вот,например массив 5 5 0 1 0 1 0 1 1 1 1 1 0 0 0 0 1 0 0 1 0 0 1 0 0 0 0 считываются два...

Работа тернарного оператора, исправить ошибку в коде
Друзья, подскажите, почему не выполняется данный код public bool ExistFile() { int...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru