Как ведут себя объявления переменных? - PullRequest
0 голосов
/ 16 декабря 2011
#include<stdio.h>
#include<conio.h>

int main(){

    char i;
    int c;

    scanf("%i",&c);
    scanf("%c",&i);// catch the new line or character introduced before x number
    printf("%i",i);// value of that character

    getch();
    return(0);
}

Программа будет вести себя так же, как и следующие объявления переменных вместо вышеуказанного объявления переменных:

this:

int c;
int *x;
int i;

или this:

int *x;
int c;
int i;

И только так: переменная c и указатель x перед переменной i .Я знаю, что эти последние объявления не имеют смысла: int i вместо char i и дополнительный указатель, который даже не нужен.Но это произошло случайно, и мне интересно, является ли это просто совпадением.

Ответы [ 2 ]

1 голос
/ 16 декабря 2011

Порядок, в котором вы объявляете свои переменные, не должен иметь никакого значения, при условии, что с остальным кодом нет ничего плохого.Порядок объявления не должен иметь ничего общего с тем, как они изложены в памяти.И даже если это так, вы ссылаетесь на переменные по имени;Если ваш код верен, ссылка на i является ссылкой на i, и компилятор будет генерировать любой код, необходимый для правильного доступа к переменной.

Теперь, если вы сделаете это:

int i;
scanf("%c", &i);

тогда вы делаете что-то не так.scanf с форматом "%i" требует аргумента char*, который указывает на объект char, в который будет сохранено значение.Вы даете ему int*, а не char*.В результате поведение вашей программы не определено;языковой стандарт ничего не говорит о том, как он будет себя вести.

Так почему же он работает правильно?Вероятно, происходит то, что scanf обрабатывает адрес int объекта i, как если бы он был указателем на char.Вероятно, это будет указывать на первый байт представления i;например, i может быть 32-битным, и указатель будет указывать на первые 8 из этих битов.(Это могут быть старшие или младшие биты, в зависимости от системы.)

Теперь, когда вы печатаете значение i:

printf("%d\n", i);

содержимое *Например, 1028 * - это 1 байт, состоящий из любого символа, который вы только что прочитали, и 3 байта мусора.Эти 3 байта мусора вполне могут быть нулями, но они могут быть чем угодно.Если мусорные байты равны 0, а первый байт является старшим байтом (т. Е. Вы находитесь на машине big-endian ), то вы, вероятно, получите "правильный "вывод.

Но не делайте этого.Поскольку поведение не определено, оно может работать «правильно» в течение многих лет, а затем эффектно проваливаться в самый неподходящий момент.

Урок здесь состоит в том, что С склонен считать, что вы знаете, что делаете.Существует много конструкций, которые имеют неопределенное поведение, что означает, что они недействительны, но ни компилятор, ни система времени выполнения не обязаны сообщать вам о наличии проблемы.В C больше, чем в большинстве других языков, программисту решать, как правильно.Компилятор (и другие инструменты) расскажет вам о некоторых ошибках, но не обо всех.

И при наличии неопределенного поведения, порядок, в котором вы объявляете свои переменные может изменить ситуацию.Например, если вы пишете код, который читает или записывает после конца переменной, может иметь значение, что там хранится.Но не поддавайтесь искушению смешивать ваши объявления, пока программа не заработает.Избавьтесь от неопределенного поведения, чтобы порядок не имел значение.

Решение: во-первых, не совершайте ошибок.(Конечно, это легче сказать, чем сделать.)

И соглашения об именах могут быть полезны.Если бы вы назвали свою char переменную c, а свою int переменную i, а не наоборот, было бы легче отслеживать, какая есть какая.

Но c - разумное имя для переменной int, используемой для хранения значений вводимых символов - не для scanf, а для getchar(), например:

int c;
while ((c = getchar()) != EOF) {
    /* ... */
}
1 голос
/ 16 декабря 2011

Функция ожидает последовательность ссылок в качестве дополнительных аргументов, каждый из которых указывает на объект типа, указанного их соответствующим тегом% в строке формата, в том же порядке. Читать о scanf

Они могут дополнительно помочь вам:

Я не понимаю, почему я не могу получить три входа в c

scanf () оставляет новый символ строки в буфере?

Что касается последней части вашего вопроса, число битов int всегда больше, чем char, поэтому это не вызовет проблемы.

...