Перепутанный, когда я должен и не должен использовать “константу” в C

ВЫБРАТЬ сумму (DISTINCT отметки) ИЗ таблицы;

Вы можете использовать этот запрос, чтобы получить сумму значений различных отметок.

6
задан Ricardo Amaral 2 April 2009 в 17:14
поделиться

11 ответов

Без указателя Вы имели бы

const Dict currPtr

который является постоянным Dict. Теперь при создании этого указателем, Вы имеете

const Dict *currPtr

который является указателем на постоянный Dict. Это не означает, что указатель является постоянным. Но это действительно означает, что Dict указал, рассматривается как постоянный

currPtr->key = 10; // error, dict is treated as constant. 

Но указатель не

currPtr = otherPtr; // possible: the pointer is not constant

Вы получили бы ошибку для второго случая при создании указателя постоянным. Сохраняя резкую dict константу также, это было бы похоже на это

const Dict * const currPtr = init;

Теперь Вы не можете установить currPtr для указания на что-то другое, потому что указатель является теперь постоянным, не, на что указывает указатель, рассматривается так. Некоторые люди как взгляд, если константа является всегда правильной к материалу, что это делает константу. Это было бы похоже на это

Dict const * const currPtr = init;

который совпадает с предыдущим отрывком. Если Вы затем читаете его справа налево, это говорит Вам, что это - "указатель константы на константу Dict". Если у Вас есть тип, не имеет значения, как Вы заказываете спецификаторы

int const a = 10;
const int b = 10;

Оба - постоянные целые числа. Именно поэтому мы могли исправить константу спецификатора типа Dict.

Теперь, если у Вас есть указатель, можно всегда притворяться, что Вы указываете на постоянный объект, даже при том, что объект не был объявлен константой. Но Вы не можете симулировать работать с объектом неконстанты, если то, на что Вы указываете, является объектом константы:

int const *p = NULL;
// doesn't work without a cast. Will at least provoke a warning
int *pn = p;

int *p = NULL;
// always works: pretending to point to something const doesn't harm.
int const *pc = p;

Обратите внимание, что при создании самого указателя константой правила отличаются от этого. Они походят на константу, относился к другим типам:

int const i = 0;
int j = i; // works. we only read the value of i. its const doesn't matter. 

int * const p = NULL;
int * q = p; // works: we only read the value of p (a null pointer).

После копирования значения в новую переменную (или указатель или не), новая переменная не подключена всегда к другой переменной, потому что чтение значения не имеет никакой ассоциативности к тому, как стоимость была создана во-первых. Константа другой переменной не имеет значения.

13
ответ дан 8 December 2019 в 03:02
поделиться

"Я добавил, что "константа" к dict аргументу в добирается () так, чтобы компилятор предупредил меня, если я пытаюсь измениться, адрес dict указывает"

В этом случае Вы имели в виду Dict *const dict, нет const Dict *dict. Вы объявили структуру как константу, не указатель на нее.

"Почему у меня должна также быть константа для currPtr"

Поскольку иначе Вы могли использовать currPtr для изменения самой структуры словаря, которая, как предполагается, является константой в этой функции.

"Строка currPtr = currPtr-> затем; действительно ли изменение является currPtr указателем, таким образом, почему компиляция не предупреждает меня об этом, если я добавил константу к currPtr"

Та же причина: это не ошибка, если константа находится в месте, Вы помещаете его. Это было бы, если бы константа была в другом месте для currPtr.

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

Нет - когда основные вызовы программы добираются, это передает значение указателя в стандартную программу, и это становится значением dict в получить функции. Но доберитесь, имеет его собственную переменную указателя, отдельную от той в основной программе. Даже если они именно так произойдут с обоими быть названными "dict", то изменение одного указателя не изменит другой.

Обе переменные указывают на ту же структуру, поэтому при использовании переменной для изменения какого-либо из полей в структуре, затем конечно, результаты будут влиять на оба бита кода. Обычно, вызванная функция "добирается", была бы операция только для чтения, таким образом, Вы правы сделать параметр const Dict *. Но я думаю причина, это правильно, немного отличается от того, что Вы думаете. Это должно защитить содержание словаря от изменения, для не защиты записи адреса его.

Однако безопасность константы является немного неловкой для связанных списков как этот. Даже когда у Вас есть константа Dict, его "следующее" поле все еще не указывает на константу. Таким образом, хотя Вы не можете изменить первый узел, система константы не защитит Вас от изменения других узлов в списке. C++ обращается к этому с перегрузкой функции, таким образом, у Вас может быть функция "getnext", которая возвращается, константа произвела, если вход является константой, но неконстанта произвела, если вход является неконстантой. Вы могли достигнуть подобной вещи в C с "getnext" и "getnext_c", последнее наличие параметра константы и возврата. Но большинство людей не беспокоится, включая стандартные библиотечные функции как strchr, который в C берет символ константы*, но возвращает неконстанту char*. strchr может поэтому случайно использоваться в C для преобразования строки константы в неконстанту один без любого предупреждения. Или сознательно, в этом случае это немного похоже на отмывающие деньги через "законный" бизнес ;-)

del () функция не требует, чтобы я добавил константу прежде currPtr и prevPtr?

Я признаюсь, что озадачен на этом. Я ожидал бы то же предупреждение, как в "добираются" - действительно ли Вы уверены, что это не там? Но параметр к del не должен быть константой так или иначе, потому что Вы потенциально изменяете поля.

7
ответ дан 8 December 2019 в 03:02
поделиться

константа Dict *dict имеет в виду это, является указателем на постоянные значения Dict

Вы могли изменить указатель, но не значения;

3
ответ дан 8 December 2019 в 03:02
поделиться

Я думаю, что Ваш основной беспорядок прибывает из недоразумения значения

const char* p;

Это определяет указатель на постоянный символ. Адрес в p может измениться, но указатель значения не может. То, что запрещается компилятором, должно измениться *p, не p.

2
ответ дан 8 December 2019 в 03:02
поделиться

Это может помочь считать объявление указателя назад:

const Dict *dict

средства

'dict' является указателем на Dict, который является постоянным.

Можно переместить адрес, на который это указывает, но структуру, на которую это указывает, рассматривают как постоянную.

2
ответ дан 8 December 2019 в 03:02
поделиться

A const вид документации программиста. Это говорит себе, что Вы не попытаетесь изменить что-либо, что было передано в const квалифицированный.

Ваш get функция должна взять a const Dict * тогда как Ваш del функция не должна. currPtr Уокер - это не изменяет логическое состояние Dict объект в Вашем get таким образом, это должно быть const квалифицированный также. Однако в Вашем del это изменяет структуру следовательно - нет const здесь.

1
ответ дан 8 December 2019 в 03:02
поделиться

Следует иметь в виду это const может появиться или на или на обе стороны * в объявлении указателя, и это семантически значительно...

const char * foo = bar;

не то же как

char * const foo = bar;

Первое говорит, что содержание const, и второе говорит, что указатель const.

Для максимального constness существует:

const char * const foo = bar;
1
ответ дан 8 December 2019 в 03:02
поделиться

Компилятор отслеживает то, что и что не является константой. Разбирание в них может быть хитрым сначала.

Для Вашей первой точки Вы являетесь передающими в const Dict *dict, что означает, что Вы обещаете, что не собираетесь изменять что-либо через dict. Затем Вы присваиваете его Dict * currptr. С тех пор currptr не const, Вы могли изменить вещи через *currptr. Компилятор должен предупредить Вас в какой-то момент, что Вы пытаетесь изменить что-то даже при том, что это - константа, и правильное место - при присвоении указателя константы на указатель неконстанты.

Для Вашей второй точки Вы пропускаете точно, что const. Если Вы имеете const Dict * currptr, Вы описываете currptr как указатель на const Dict, значение Вас может измениться currptr но нет *currptr. Можно сделать currptr const с Dict * const currptr, или сделайте это указателем константы на значение константы с const Dick * const currptr.

Я на самом деле не понимаю Вашу третью точку. Необходимо получить предупреждение компилятора от del() поскольку Вы отправили его, так как Вы присваиваете указатель на значение константы к указателю на значение. Вы должны иметь prevptr неконстанта, так как Вы используете его для изменения значения. Функциональная подпись должна быть Dict *del(Dict *dict, int key), с тех пор, как это, Вы обещаете не изменить что-либо dict указывает и делает его так или иначе.

1
ответ дан 8 December 2019 в 03:02
поделиться

Я получаю большинство вещей Вы, люди говорят, что я не получаю теперь, это...

Считайте следующий список () функцией:

void list(Dict *dict) {
    if(!dict) return;

    while(dict) {
        printf("KEY: %d\n", dict->key);
        printf("VALUE: %s\n", dict->value);

        dict = dict->next;
    }
}

(более просто использовать этого вместо получения () одно),

В моем основном у меня есть два вызова к этой функции, как:

list(dict);
list(dict);

Конечно, dict имеет некоторые вставленные записи...

К моему пониманию только первый список () должен произвести что-то, потому что dict указатель изменяется в списке () функция и в конечном счете укажет на ПУСТОЙ УКАЗАТЕЛЬ (иначе, мы были бы в бесконечном цикле с условием продолжения в списке () вызовом). Что происходит, который является вторым списком (), вызов также производит тот же словарь, когда я думаю, что он ничего не должен производить, потому что dict должен быть ПУСТЫМ, нет?

0
ответ дан 8 December 2019 в 03:02
поделиться

Реклама 1 и 2: const в прототипе относится Dict, это означает

char *get(const Dict *dict, int key)

чтения как... функция с (неконстанта) аргумент указателя типа на постоянный Dict..., что означает Вас, могут измениться dict, но не, например. dict->next.

Если Вы хотите получить эффект, Вы, вероятно, предназначили, объявите это как это

char *get(Dict * const dict, int key)

Правило: const относится к слову, которое является слева от него, кроме тех случаев, когда это является первым в имени типа, и затем это относится к следующему слову.

Кроме того, изменение dict не изменяет указатель в основной программе, так как указатель передается значением.

При присвоении к currDict указатель, компилятор проверяет, что типы совместимы, который, в этом случае, означает, что можно только добавить верхний уровень const спецификаторы, не удаляют, как Вы делаете.

Где должен Вы использовать константу:

В get() функция, необходимо использовать константу на всех Dicts (как Вы делаете), поскольку Вы, вероятно, не хотите изменять словарь там.

В del(), функция, я не использовал бы никого consts, так как данные должны быть изменены там. Хорошая подпись для него была бы:

char *get(Dict ** dict, int key)

таким образом, Вы смогли бы изменить указатель функции вызова для удаления первого элемента.

1
ответ дан 8 December 2019 в 03:02
поделиться

"Фиктивное Руководство по константе":

Используйте его каждый раз, когда Вы можете.

0
ответ дан 8 December 2019 в 03:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: