Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Область видимости переменнойСтр 1 из 11Следующая ⇒
Переменные бываю локальными (объявленными внутри какой-нибудь функции) и глобальными. Глобальная переменная видна всем функциям, объявленным в данном файле. Локальная переменная ограничена своей областью видимости. Когда мы говорим, что переменная "видна в каком-то месте", это означает, что в этом месте она определена и её можно использовать. Например, рассмотрим программу, в которой есть глобальная переменная
#include<conio.h> #include<stdio.h>
int global = 100;
void foo() { printf("foo: %d\n", global); }
void bar(int global) { printf("bar: %d\n", global); }
int main() { foo(); bar(333); getch(); }
Будет выведено
foo: 100 bar: 333
Здесь глобальная переменная global видна всем функциям. Но аргумент функции затирает глобальную переменную, поэтому при передаче аргумента 333 выводится локальное значение 333. Вот другой пример.
#include<conio.h> #include<stdio.h>
int global = 100;
int main() { int global = 555; printf("%d\n", global); getch(); }
Программа выведет
Также, как и в прошлом случае, локальная переменная "важнее". Переменная, объявленная в некоторой области видимости не видна вне её, например.
#include<conio.h> #include<stdio.h>
int global = 100;
int main() { int x = 10; { int y = 30; printf("%d", x); } printf("%d", y); }
Этот пример не скомпилируется, потому что переменная y существует только внутри своего блока. Вот ещё пример, когда переменные, объявленные внутри блока перекрывают друг друга
#include<conio.h> #include<stdio.h>
int global = 100;
int main() { int x = 10; { int x = 20; { int x = 30; printf("%d\n", x); } printf("%d\n", x); } printf("%d\n", x); getch(); }
Программа выведет:
Глобальных переменных необходимо избегать. Очень часто можно услышать такое. Давайте попытаемся разобраться, почему. В ваших простых проектах глобальные переменные выглядят вполне нормально. Но представьте, что у вас приложение, которое: · разрабатывается несколькими людьми и состоит из сотен тысяч строк кода; · работает в несколько потоков. Во-первых, глобальная переменная, если она видна всем, может быть изменена любой частью программы. Вы изменили глобальную переменную, хотите её записать, а другая часть программы уже перезаписала в неё другое значение (на самом деле это целый класс проблем, которые возникают в многопоточной среде).
Во-вторых, при больших размерах проекта не уследить, кто и когда насоздавал глобальных переменных. В приведённых выше примерах видно, как переменные могут перекрывать друг друга, то же произойдёт и в крупном проекте. Переменные могут быть не только целочисленными и с плавающей точкой. Существует множество других типов, которые мы будем изучать в дальнейшем.
Тема №3 Оператор присваивания Когда мы работаем с переменными, необходимо изменять их значение. Это делается с помощью оператора присваивания «=».
#include<conio.h> #include<stdio.h>
int main() { signed long long a, b, c; a = 1234567890123456789LL; b = -1234567890123456789LL; c = 123;
printf("%lld\n", a); printf("%lld\n", b); printf("%lld\n", c); getch(); }
Оператор присваивания имеет особенность – он возвращает правое значение. Это значит, что можно использовать несколько операторов присваивания подряд, по цепочке.
#include<conio.h> #include<stdio.h>
int main() { unsigned a, b, c; a = b = c = 10; printf("%u = %u = %u = 10", a, b, c); getch(); }
В этом примере переменной c присваивается значение 10, после чего оператор присваивания возвращает значение 10, которое используется следующим оператором, и присваивает значение 10 переменной b, после чего возвращает значение 10, которое используется следующим оператором. Это свойство - возвращать значение - часто используется. Например, при выделении памяти мы можем узнать, была ли действительно выделена память.
#include<conio.h> #include<stdio.h> #include<stdlib.h>
int main() { int *a = NULL;
printf("Try to allocate memory\n"); if (a = (int*)malloc(1024*1024*1024 * sizeof(int))) { printf("Memory was allocated"); } else { printf("Error: can't allocate memory"); } getch(); free(a); }
Здесь одновременно выделяется память и проверяется, что было возвращено при попытке получить память. Этот же пример может быть записан и так
a = (int*)malloc(1024*1024*1024 * sizeof(int)); if (a) { printf("Memory was allocated"); } else { printf("Error: can't allocate memory"); }
(вам этот пример кажется непонятным, здесь важно для вас только использование оператора =). Rvalue и lvalue Любая переменная связана с адресом в памяти и хранит некоторое значение. Выражение типа
int i; i = 20;
говорит о том, что мы заносим в область памяти, на которую указывает переменная i значение 20. Выражение
20 += 3;
не имеет смысла, поскольку 20 - это литерал, значение, которое не связано с областью памяти. Для обозначения объектов, которым может быть присвоено значение, используется понятие lvalue (буквально, то, что может стоять слева от оператора присваивания). Для обозначения объектов, которые имеют только значения, используют выражение rvalue (то, что стоит справа от оператора присваивания). lvalues в свою очередь делят на modifiable lvalues, которые могут быть изменены, и non-modifiable lvalues, которые связаны с областью памяти, но не могут быть изменены, например, константы. В том случае, если lvalue стоит справа от оператора присваивания, например:
int i, j; j = 20; i = j;
то происходит lvalue-to-rvalue convertion, преобразование lvalue к rvalue. К rvalue относятся результаты арифметических выражений, преобразование не к ссылочным типам, результат постфиксных операций ++ и --, литералы за исключением строк. К lvalue относятся переменные, выражения ссылочных типов, результат операции разыменования *, строковые литералы, результат префиксных операций ++ и -- над ссылочными типами. Имена функций и массивов, также объявленные как немодифицируемые объекты, являются non-modifiable lvalues. Ввод-вывод Форматированный вывод Сегодня мы рассмотрим две важные функции форматированного ввода и вывода. Устройство и работу этих функций полностью можно понять только после изучения работы с указателями и функций с переменным числом параметров. Но пользоваться этими функциями необходимо уже сейчас, так что некоторые моменты придётся пропустить. Функция форматированного вывода printf получает в качестве аргументов строку формат и аргументы, которые необходимо вывести в соответствии с форматом, и возвращает число выведенных символов. В случае ошибки возвращает отрицательное значение и устанавливает значение ferror. Если произошло несколько ошибок, errno равно EILSEQ (Ошибочная последовательность байтов). int printf (const char * format,...);
#include <stdio.h> #include <conio.h>
void main() { //функция не получает никаких аргументов, кроме строки printf("Hello world"); getch(); }
Функция проходит по строке и заменяет первое вхождение %<спецификатор формата> на первый аргумент, второе вхождение %<спецификатор формата> на второй аргумент и т.д. Далее мы будем просто рассматривать список флагов и примеры использования. Общий синтаксис спецификатора формата
%[флаги][ширина][.точность][длина]спецификатор
Спецификатор – это самый важный компонент. Он определяет тип переменной и способ её вывода.
Примеры
#include <stdio.h> #include <conio.h>
void main() { int a = 0x77, b = -20; char c = 'F'; float f = 12.2341524; double d = 2e8; char* string = "Hello, World!";
printf("%s\n", string); printf("a = %d, b = %d\n", a, b); printf("a = %u, b = %u\n", a, b); printf("a = %x, b = %X\n", a, b); printf("dec a = %d, oct a = %o, hex a = %x\n", a, a, a); printf("floating point f = %f, exp f = %e\n", f, f); printf("double d = %f or %E\n", d, d); printf("not all compiler support %a\n", f); printf("character c = %c, as number c = %d", c, c); printf("address of string is %p", string); getch(); }
Строка формата также может включать в себя следующие необязательные суб-спецификаторы: · флаг, · ширина, ·.точность и · модификатор (именно в таком порядке).
Примеры
#include <stdio.h> #include <conio.h>
void main() { int a = 0x77, b = -20; char c = 'F'; float f = 12.2341524; double d = 2e2; char* string = "Hello, World!";
printf("%.3f\n", f); printf("%.*f\n", 2, f); printf("%010.3f\n", d); printf("%*d\n", 6, a); printf("%+d\n", b); printf("%0.6d\n", a); printf("%.f\n", d); printf("%.4s", string); getch(); }
Суб-спецификатор длины изменяет длину типа. В случае, если длина не совпадает с типом, по возможности происходит преобразование до нужного типа.
Примеры
#include <stdio.h> #include <conio.h>
void main() { long long x = 12300000000579099123; short i = 10; printf("%llu\n", x); printf("%d\n", i); printf("%hd\n", i); getch(); }
Форматированный ввод Рассмотрим форматированный ввод функцией scanf.
int scanf(const char*,...)
Функция принимает строку формата ввода (она похожа на строку формата printf) и адреса, по которым необходимо записать считанные данные. Возвращает количество успешно проинициализированных аргументов. Формат спецификатора ввода
%[*][ширина][длинна]спецификатор
Как и в printf, ширина, заданная символом * ожидает аргумента, который будт задавать ширину. Флаг длина совпадает с таким же флагом функции printf. Примеры.
#include <stdio.h> #include <conio.h>
void main() { int year, month, day; char buffer[128]; int count; //Требует форматированного ввода, например 2013:12:12 printf("Enter data like x:x:x = "); scanf("%d:%d:%d", &year, &month, &day); printf("year = %d\nmonth = %d, day = %d\n", year, month, day); //Считываем строку, не более 127 символов. При считывании в массив писать & не надо, //так как массив подменяется указателем printf("Enter string = "); scanf("%127s", buffer); printf("%s", buffer); getch(); }
Кроме функций scanf и printf есть ещё ряд функций, которые позволяют получать вводимые данные.
int getch() int getchar()
Возвращает введённый символ, при этом не выводит его на консоль.
#include <stdio.h> #include <conio.h>
void main() { char c = 0; do { c = getch(); printf("%c", c); } while (c!= 'q'); }
Функция fgets:
char * fgets (char * str, int num, FILE * stream)
Функция позволяет считывать строку с пробельными символами. Несмотря на то, что она работает с файлом, можно с её помощью считывать и из стандартного потока ввода. Её преимущество относительно gets в том, что она позволяет указать максимальный размер считываемой строки и заканчивает строку терминальным символом.
#include <stdio.h> #include <conio.h> #include <stdlib.h>
void main() { char buffer[128]; //Считываем из стандартного потока ввода fgets(buffer, 127, stdin); printf("%s", buffer); //Этим можно заменить ожидание ввода символа scanf("1"); }
Это не полный набор различных функций символьного ввода и вывода. Таких функций много, но очень многие из них небезопасны, поэтому перед использованием внимательно читайте документацию. Непечатные символы В си определён ряд символов, которые не выводятся на печать, но позволяют производить форматирование вывода. Эти символы можно задавать в виде численных значений, либо в виде эскейп-последовательностей: · символа, · экранированного обратным слешем.
#include <stdio.h> #include <conio.h>
void main() { char backspace = 0x08; //Выводим с использованием символа переноса строки printf("Hello\nWorld\n"); //Выводим символ переноса строки через его значение printf("Hello%cWorld\n", 0x0a); //"Выводим" сигнал printf("\a"); //Выводим сигнал, как символ printf("%c", '\a'); //Выводим сигнал через шестнадцатеричное значение printf("%c", 0x07); printf("This is sparta!!!\b\b%c", backspace); printf(" "); getch(); }
Тема №4
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Последнее изменение этой страницы: 2017-01-20; просмотров: 256; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.144.140.151 (0.146 с.) |