0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
1

Некоторые трудности с Си

16.03.2017, 23:18. Показов 1364. Ответов 33

Здравствуйте. Помогите исправить ошибку в программе.



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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdio.h>
#include <malloc.h>
#include <locale.h>
#include <string.h>
#define MAXSET 1000
#define ERROR "Ошибка: Некорректный ввод\n"
 
int GetDigit_0_999();
char *GetLine();
char *CatLine(char *ptr_line, char *bufline);
void WriteLines(char **ptr_lines);
int LenLine(char *ptr_line);
 
int main()
{
    setlocale(LC_ALL, "RUS");
    int i, type, num = 0;// dig, dig2, first, second;
    char **ptr_lines = (char **)malloc(1);
    char *ptr_line = NULL;
    char Menu[][40] = {
        "Выход\n",
        "Ввести строку\n",
        "Взять подстроку\n",
        "Склеить 2 строки\n",
        "Разбить строку на слова\n",
        "Вывести доступные строки\n",
        "Узнать длину строки\n",
        "Удалить строку\n"
    };
    do {
        for (i = 0; i < 8; i++)
            printf("%d.%s", i, Menu[i]);
        printf("Выберите действие:");
        switch (type = GetDigit_0_999()) {
        case 1:
            if (ptr_line = GetLine()) {
                *(ptr_lines + num++) = ptr_line;
                ptr_lines = (char **)realloc(ptr_lines, num + 1); // Эта строчка делает что-то не то
                *(ptr_lines + num) = NULL;
            }
            else
                printf("%s", ERROR);
            break;
        case 5:
            if (ptr_lines)
                WriteLines(ptr_lines);
            else
                printf("Нет доступных строк\n");
        }
    } while (type);
    return 0;
}
 
int GetDigit_0_999() //РАБОТАЕТ
{
    unsigned int dig;
    scanf_s("%u", &dig);
    while (getchar() != '\n');
    if (dig >= 0 && dig < 1000)
        return dig;
    return EOF;
}
 
char *GetLine() //РАБОТАЕТ, необходимы тесты
{
    char *ptr_line = (char *)malloc(1);
    char buf[101];
    int n, len = 0;
    *ptr_line = '\0';
    do {
        n = scanf_s("%50[^\n]", buf, 101);
        if (n > 0) {
            len += LenLine(buf);
            ptr_line = (char *)realloc(ptr_line, len + 1);
            CatLine(ptr_line, buf);
        }
        else if (n == 0)
            scanf_s("%*c");
        else {
            free(ptr_line);
            ptr_line = NULL;
        }
    } while (n > 0);
    return ptr_line;
}
 
char *CatLine(char *ptr_line, char *bufline) //РАБОТАЕТ
{
    char *ptr_line2 = ptr_line;
    for (; *ptr_line2; ptr_line2++);
    while (*ptr_line2++ = *bufline++);
    return ptr_line;
}
 
void WriteLines(char **ptr_lines) //
{
    int i = 0;
    while (ptr_lines) {
        printf("%s\n", *ptr_lines++);
    }
}
 
int LenLine(char *ptr_line) //РАБОТАЕТ
{
    char *ptr_line2 = ptr_line;
    for (; *ptr_line; ptr_line++);
    return ptr_line - ptr_line2;
}
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
16.03.2017, 23:18
Ответы с готовыми решениями:

Некоторые трудности с ЦАП
Помогите разобраться.Сделал схему ЦАП.Преподаватель говорит чтобы на каждом следующем резисторе...

Некоторые трудности с наследованием
Всё описание в комментариях в коде. Спасибо. //Мне нужны функции в классе B, выполняющие то же...

Библиотека Grab , некоторые трудности
from grab import Grab Grab(log_file='out.html').go('http://yandex.ru') Библиотека...

String to int и некоторые другие трудности
Здравствуйте. При написании не большого консольного приложения возникли пара вопросов. Суть...

33
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 02:46 2
Цитата Сообщение от Twolka Посмотреть сообщение
C
1
#include <malloc.h>
Зачем это? В стандартной библиотеке нет такого заголовочного файла.

Цитата Сообщение от Twolka Посмотреть сообщение
C
1
2
3
4
5
int GetDigit_0_999();
char *GetLine();
char *CatLine(char *ptr_line, char *bufline);
void WriteLines(char **ptr_lines);
int LenLine(char *ptr_line);
Если уж вы взялись объявлять прототипы функций, то прототип функции без параметров в С объявляется со списком параметров (void). Не (), а именно (void).

Цитата Сообщение от Twolka Посмотреть сообщение
C
1
2
3
char **ptr_lines = (char **)malloc(1);
...
ptr_lines = (char **)realloc(ptr_lines, num + 1);
Так а в чем была идея? Почему для массива из char * выделяется какой-то жалкий 1 байт? Потом 2 байта...

И зачем понаставлено приведений типа на результат функций выделения памяти?
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 02:57  [ТС] 3
Байты: Я же не знаю, сколько строк хочет ввести пользователь. Каждой новой строке выделяется отдельное место.

Приведения: Так вроде же сами функции выделения памяти *void возвращают? А мне нужны эти указатели в виде *char. Или я не прав?

<malloc.h>: Функция malloc() (предполагаю, что и realloc() тоже) не работает без этой библиотеки

Добавлено через 3 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Зачем это? В стандартной библиотеке нет такого заголовочного файла.



Если уж вы взялись объявлять прототипы функций, то прототип функции без параметров в С объявляется со списком параметров (void). Не (), а именно (void).



Так а в чем была идея? Почему для массива из char * выделяется какой-то жалкий 1 байт? Потом 2 байта...

И зачем понаставлено приведений типа на результат функций выделения памяти?
Хорошо, про параметры запомню
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:20 4
Цитата Сообщение от Twolka Посмотреть сообщение
Байты: Я же не знаю, сколько строк хочет ввести пользователь. Каждой новой строке выделяется отдельное место.
Каждая строка у вас представляется отдельным указателем в массиве указателей. Указатель обычно занимает 4 или 8 байт памяти (в зависимости от платформы). Вы же для хранения одного указателя выделяете 1 байт памяти (!). Когда вам надо хранить 2 указателя, вы выделяете 2 байта памяти и т.д.

Как образом вы рассчитываете запихнуть указатель размером 4 (или 8) байтов в один байт памяти???

Цитата Сообщение от Twolka Посмотреть сообщение
Приведения: Так вроде же сами функции выделения памяти *void возвращают? А мне нужны эти указатели в виде *char. Или я не прав?
Именно void *! В языке C тип void * является неявно приводимым к любому другому объектному указательному типу. Т.е. компилятор сам за вас все прекрасно приведет. Не надо захламлять код явными приведениями. Ненужные приведения типов - это всегда признак дурного стиля гамнокода.

Функция realloc, например, требует на вход параметры типа void * и size_t. То есть согласно вашей же логике вы должны вызывать ее как
C
1
realloc((void *) ptr_lines, (size_t) (num + 1))
. Но вы же этого не делаете, так? Почему же на возвращаемое значение вам так хочется наложить явный каст?

Цитата Сообщение от Twolka Посмотреть сообщение
<malloc.h>: Функция malloc() (предполагаю, что и realloc() тоже) не работает без этой библиотеки
Во-первых, это не "библиотека", а заголовочный файл. Библиотека у вас используется одна - стандартная.

Во-вторых, эти функции работы с памятью объявлены в стандартном заголовочном файле <stdlib.h>. Вот его и надо подключить. Заголовочного файла <malloc.h>, еще раз, в стандартной библиотеке нет.

Уж что-что, а <stdlib.h>, как правило, нужен везде, т.е. его смело можно включать безусловно.
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:24  [ТС] 5
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Каждая строка у вас представляется отдельным указателем в массиве указателей. Указатель обычно занимает 4 или 8 байт памяти (в зависимости от платформы). Вы же для хранения одного указателя выделяете 1 байт памяти (!). Когда вам надо хранить 2 указателя, вы выделяете 2 байта памяти и т.д.
Как образом вы рассчитываете запихнуть указатель размером 4 (или 8) байтов в один байт памяти???
Т.е. я должен написать: (4 или 8)
C
1
realloc(ptr_lines, 4*(num + 1))
?

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Т.е. компилятор сам за вас все прекрасно приведет.
Учту
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:26 6
Лучший ответ Сообщение было отмечено Twolka как решение

Решение

Цитата Сообщение от Twolka Посмотреть сообщение
Т.е. я должен написать:
C
1
realloc(ptr_lines, 4*(num + 1))
?
Идея - правильная.

Но написать лучше вот так

C
1
ptr_lines = realloc(ptr_lines, (num + 1) * sizeof(char *));
Именно для таких случаев оператор sizeof и предназначен.

А еще лучше вообще избавиться от упоминаний конкретных типов и написать так

C
1
ptr_lines = realloc(ptr_lines, (num + 1) * sizeof *ptr_lines);
И не забудьте исправить ту же ошибку в malloc.
1
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:35  [ТС] 7
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Во-вторых, эти функции работы с памятью объявлены в стандартном заголовочном файле <stdlib.h>. Вот его и надо подключить.
Тогда зачем созданы заголовочные файлы типа <malloc.h>?

Добавлено через 7 минут
Без явных преобразований выводит вот такие вещи:

значение типа "void *" нельзя использовать для инициализации сущности типа "char **"
невозможно преобразовать "void *" в "char **"
значение типа "void *" нельзя присвоить сущности типа "char **"
инициализация: невозможно преобразовать "void *" в "char **"
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:37 8
Цитата Сообщение от Twolka Посмотреть сообщение
Тогда зачем созданы заголовочные файлы типа <malloc.h>?
Что значит "зачем"? Если вы заглянете в какую-нибудь реализацию стандартной библиотеки, вы увидите там великое множество разношерстных заголовочных файлов, созданных для внутренних цели самой библиотеки. Эти заголовочные файлы - внутренние детали реализации, о которых вам знать не нужно и не положено. Если вы ни с того ни с сего начнете их "включать" в свой код, то ничего путного из этого не получится.

P.S. Во времена динозавров в языке С действительно существовал заголовочный файл <malloc.h>. Но в стандартном С от него отказались, а объявления функций работы с памятью поместили в <stdlib.h>. У вас же в вашем компиляторе дух этого <malloc.h> еще продолжает болтаться чисто ради совместимости с каким-нибудь замшелым старинным кодом.
1
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:38  [ТС] 9
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
И не забудьте исправить ту же ошибку в malloc.
C
1
char **ptr_lines = malloc(sizeof(**ptr_lines));
Вот так?
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:40 10
Цитата Сообщение от Twolka Посмотреть сообщение
Без явных преобразований выводит вот такие вещи:
Это говорит о том, что все это время вы нас обманывали. Этот форум посвящен языку программирования С. Вы же свою программу компилируете, как С++ программу. С++ - совершенно другой язык. В языке С++ такой каст действительно нужен.

Вы уж определитесь, на каком языке вы пишете. И, соответственно, выбирайте форум для своих вопросов правильно.
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:40  [ТС] 11
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
У вас же в вашем компиляторе дух этого <malloc.h> еще продолжает болтаться чисто ради совместимости с каким-нибудь замшелым старинным кодом.
Нет, скорее просто заставили лабу писать на Си, но ничему не научили
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:42 12
Цитата Сообщение от Twolka Посмотреть сообщение
C
1
char **ptr_lines = malloc(sizeof(**ptr_lines));
Вот так?
Нет.

C
1
char **ptr_lines = malloc(sizeof *ptr_lines); // Скобки можно оставить, но они не нужны
Правило такое: Если под sizeof вы используете именно выражение (а не имя типа), то звездочка под sizeof всегда будет ровно одна.
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:44  [ТС] 13
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Это говорит о том, что все это время вы нас обманывали. Этот форму посвящен языку программирования С. Вы же свою программу компилируете, как С++ программу. С++ - совершенно другой язык
Хм... Я компилирую в Visual studio 2015. Просто начитался в интернете, что и то, и то работает, а на C++ не обращать внимания

Добавлено через 1 минуту
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Правило такое: Если под sizeof вы используете именно выражение (а не имя типа), то звездочка под sizeof всегда будет ровно одна
ОК.
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:46 14
Цитата Сообщение от Twolka Посмотреть сообщение
Хм... Я компилирую в Visual studio 2015. Просто начитался в интернете, что и то, и то работает
Никаких проблем с Visual Studio 2015. Просто если вы хотите писать код именно на С, то давайте своим файлам расширение .c, а не .cpp. Тогда они автоматически будут компилироваться Visual Studio как С.

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

Цитата Сообщение от Twolka Посмотреть сообщение
а на C++ не обращать внимания
Это плохой совет. С и С++ - очень разные языки.
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 03:48  [ТС] 15
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Но вы же этого не делаете, так? Почему же на возвращаемое значение вам так хочется наложить явный каст?
Ну... например потому, что такой тип записи - это единственный, который я видел (P.S. большую часть ф-ции GetLine() я написал не сам)
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 03:59 16
Цитата Сообщение от Twolka Посмотреть сообщение
большую часть ф-ции GetLine() я написал не сам
В функции GetLine у вас тоже есть работа с динамической памятью и вызовы malloc/realloc. В этом случае вы работаете с массивами из элементов типа char. Тип char отличается тем, что его размер в С (и С++) всегда равен 1. Это в свою очередь значит, что в этих вызовах malloc/realloc умножать все на sizeof явного смысла нет - это будет умножение на 1. И многие предпочитают этого не делать (именно когда работа идет с массивами [signed/unsigned] char). То есть с этой точки зрения исправлять в GetLine ничего не надо.

Однако я бы все равно посоветовал вам придерживаться формальной идиомы: для выделения массива, указуемого указателем p пользоваться следующей формой записи

C
1
p = malloc(n * sizeof *p)
Т.е. полностью абстрагироваться от конкретных типов. А надо ли выполнять умножение на 1, на 4 или на 25 - это компилятор сам разберется.

В общем, исправлять ли malloc/realloc в GetLine или оставить, как есть - вам решать.
2
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 04:06  [ТС] 17
А как насчёт приведения к типу char*?

Добавлено через 35 секунд
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Т.е. полностью абстрагироваться от конкретных типов. А надо ли выполнять умножение на 1, на 4 или на 25 - это компилятор сам разберется.
В общем, исправлять ли malloc/realloc в GetLine или оставить, как есть - вам решать.
Последую вашему совету
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 04:14 18
Цитата Сообщение от Twolka Посмотреть сообщение
А как насчёт приведения к типу char*?
Как я уже говорил выше, в С коде это приведение - ненужно и неуместно. Выжечь напалмом.

А если вы продолжаете компилировать свой код как С++, то от этого приведения никуда не денешься - придется приводить.
0
0 / 0 / 0
Регистрация: 16.03.2017
Сообщений: 51
17.03.2017, 04:21  [ТС] 19
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Как я уже говорил выше, в С коде это приведение - ненужно и неуместно. Выжечь напалмом.
А если вы продолжаете компилировать свой код как С++, то от этого приведения никуда не денешься - придется приводить.
Теперь никакого Си++... Но... что-то <stdlib.h> со мной не дружит

Добавлено через 1 минуту
не удается восстановить после предыдущих ошибок; остановка компиляции
невозможно обновить базу данных программы "C:\Users\Twolka\Desktop\D.R.O.Z.D Example\Ex 1\Debug\vc140.pdb" Ex 1 c:\users\twolka\desktop\d.r.o.z.d example\ex 1\source.c
0
С чаем беда...
Эксперт CЭксперт С++
10001 / 5350 / 1464
Регистрация: 18.10.2014
Сообщений: 12,898
17.03.2017, 04:26 20
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Правило такое: Если под sizeof вы используете именно выражение (а не имя типа), то звездочка под sizeof всегда будет ровно одна.
Я не совсем правильно выразился. При использовании такой идиомы для определения размера памяти, количество "звездочек" под sizeof обычно будет ровно на одну больше, чем в выражении-получателе результата

C
1
2
3
p = malloc(n * sizeof *p);
**q = calloc(m, sizeof ***q);
// И т.п.
Добавлено через 1 минуту
Цитата Сообщение от Twolka Посмотреть сообщение
не удается восстановить после предыдущих ошибок; остановка компиляции
Ну так а в чем заключаются эти "предыдущие ошибки"?

Исправление ошибок в С и С++ программах обычно начинают с самой первой, а не с последней ошибки.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
17.03.2017, 04:26
Помогаю со студенческими работами здесь

SQL Запросы в Базе Данных (SELECT, DELETE). Возникли некоторые трудности в их составлении
Здравствуйте, мне нужно сделать следующие запросы в базе данных &quot;Автовокзал&quot; (схема во вложениях):...

Некоторые exe файлы открываются, некоторые - нет. На десктопе все открывается
Привет ребят. У меня следующая заморочка. Я как-то решил изменить имя моего компьютера на...

Не работают некоторые кнопки и не заполняются некоторые поля во всех браузерах
Добрый день! Не работают некоторые кнопки и не заполняются некоторые поля во всех браузерах....

Главная функция (вводит некоторые значения и передает их и ссылки на некоторые переменные в функцию)
Написать главную функцию, которая вводит некоторые значения и передает их и ссылки на некоторые...

Почему при использовании компонента TMediaPlayer ,некоторые mp3 открываются а некоторые нет?
Почему при использовании компонента TMediaPlayer ,некоторые mp3 открываются а некоторые нет ...

При наложении 2-3 панелей, некоторые пропадают, а некоторые остаются
Здрасте! Проблема такая... При наложении 2-3 панелей. некоторые пропадают ,а некоторые остаются....


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2022, CyberForum.ru