Вывод данных в языке Си с помощью функции printf



Обращение к функции printf имеет следующий вид:

printf ( s 1, s 2);

Здесь s 1 – строка вывода, s 2 – список выводимых переменных.

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

%[флаг][ширина][.точность][модификатор]тип.

 

Таблица 2.5. Символы управления форматированием

Параметр Назначение                   

Флаги

- Выравнивание числа влево. Правая сторона дополняется пробелами. По умолчанию выравнивание вправо.
+ Перед числом выводится знак «+» или «-»
Пробел Перед положительным числом выводится пробел, перед отрицательным – «-»
# Выводится код системы счисления: 0 – перед восьмеричным числом, 0х (0Х) перед шестнадцатеричным числом.

Ширина

n Ширина поля вывода. Если n позиций недостаточно, то поле вывода расширяется до минимально необходимого. Незаполненные позиции заполняются пробелами.
0n То же, что и n, но незаполненные позиции заполняются нулями.

Точность

ничего Точность по умолчанию
n Для типов e, E, f выводить n знаков после десятичной точки

Модификатор

h Для d, i, o, u, x, X тип short int
l Для d, i, o, u, x, X тип long int

Тип

с При вводе символьный тип char, при выводе один байт.
d Десятичное int со знаком
i Десятичное int со знаком
o Восьмеричное int unsigned
u Десятичное int unsigned
x, X Шестнадцатеричное int unsigned, при х используются символы a - f, при Х – A - F.
f Значение со знаком вида [-]dddd.dddd
e Значение со знаком вида [-]d.dddde[+|-]ddd
E Значение со знаком вида [-]d.ddddE[+|-]ddd
g Значение со знаком типа e или f в зависимости от значения и точности
G Значение со знаком типа e или F в зависимости от значения и точности
s Строка символов

 


Некоторые специальные символы

Символ Назначение
\b Сдвиг текущей позиции влево
\n Перевод строки
\r Перевод в начало строки, не переходя на новую строку
\t Горизонтальная табуляция
\’ Символ одинарной кавычки
\’’ Символ двойной кавычки
\? Символ ?

Ввод данных в языке Си с помощью функции scanf

scanf ( s 1, s 2);

Здесь s 1 – список форматов вывода; s 2 – список адресов вводимых переменных.

% тип

scanf("%f%f",&a,&b);

scanf("%f%d",&c,&d);

 printf("a=");

 scanf ("% f ",& a );

 

Вывод по - русски

#include <windows.h>

#include <iostream.h>

void main()

{

char name[14];

CharToOem("Пример", name);

cout<<name<<"\n";

}

 

Вывод данных в C++ с помощью функции cout

 

#include <iostream.h>

cout<<"X="<<X;

cout<<"x="<<x<<"y="<<y<<"\n";

cout<<"x="<<x<<"y="<<y<<endl;

cout<<''Summa =''<<x+y;

 


Ввод данных в C++ с помощью функции cin

 

#include <iostream.h>

cin>>a>>b;

cin>>c;

Указатели и массивы

Для работы с адресами памяти используются указатели.

int *a; // указатель на переменную целого типа float *addr_f; // указатель на переменную вещественного типа.

Размер памяти для переменной-указателя зависит от конфигурации машины. Конкретный адрес является указателем и получается с помощью операции & (адресации). Адресация не может применяться к переменным класса памяти register и к битовым полям структур /2/.

Разадресация * применяется для получения значения величины, указатель которой известен. Если значение указателя нулевое, то результат разадресации непредсказуем.

int *рa, x; int a[20]; double d;

рa= &a[5]; // это адрес 6-го элемента массива а

х = *рa; // x присваивается значение 6-го элемента массива а

if (x==*&x) cout<<"true\n"; d=*(double *)(&x);

// адрес х преобразуется к указателю на double и d=x.

Указатель - это переменная, содержащая адрес другой переменной. Указатели очень широко используются в языке Cи. Это происходит отчасти потому, что иногда они дают единственную возможность выразить нужное действие, отчасти потому, что они обычно ведут к более компактным и эффективным программам, чем те, которые могут быть получены другими способами. Так как указатель содержит адрес объекта, это дает возможность "косвенного" доступа к этому объекту через указатель /1/. Предположим, что X - переменная, например, типа int, а РX - указатель, созданный неким еще не указанным способом. Унарная операция & выдает адрес объекта, так что оператор РX = &X; присваивает адрес X переменной РX; говорят, что РX "указывает" на X. Операция & применима только к переменным и элементам массива, конструкции вида &(X-1) и &3 являются незаконными. Нельзя также получить адрес регистровой переменной.

Унарная операция * рассматривает свой операнд как адрес конечной цели и обращается по этому адресу, чтобы извлечь содержимое. Следовательно, если Y тоже имеет тип int, то Y = *РX; присваивает Y содержимое того, на что указывает РX. Последовательность РX = &X; Y = *РX; присваивает Y то же самое значение, что и оператор Y = X; Переменные, участвующие во всем этом, необходимо описать: int X, Y; int *РX; Описание указателя int *РX; должно рассматриваться как мнемоническое; оно говорит, что комбинация *РX имеет тип int. Это означает, что если РX появляется в контексте *РX, то это эквивалентно переменной тип int. Фактически синтаксис описания переменной имитирует синтаксис выражений, в которых эта переменная может появляться. Это замечание полезно во всех случаях, связанных со сложными описаниями.

Например, double atof(), *DР; говорит, что atof() и *DР имеют в выражениях значения типа double.

Указатели могут входить в выражения. Например, если РX указывает на целое X, то *РX может появляться в любом контексте, где может встретиться X. Оператор Y = *РX + 1; присваивает Y значение, на 1 большее значения X; printf("%d\n", *РX) печатает текущее значение X; D = sqrt((double) *РX) получает в D квадратный корень из X, причем до передачи функции sqrt значение X преобразуется к типу double. В выражениях вида Y = *РX + 1 унарные операции * и & связны со своим операндом более крепко, чем арифметические операции, так что такое выражение берет то значение, на которое указывает РX, прибавляет 1 и присваивает результат переменной Y.

Ссылки на указатели могут появляться и в левой части присваивания. Если РX указывает на X, то *РX = 0 полагает X равным нулю, *РX += 1 увеличивает его на единицу, как и выражение (*РX)++. Круглые скобки в последнем примере необходимы; если их опустить, то это выражение увеличит РX, а не ту переменную, на которую он указывает. Если РY - другой указатель на переменную типа int, то РY = РX копирует содержимое РX в РY, в результате чего РY указывает на то же, что и РX.

Массив рассматривается как набор элементов одного типа. Чтобы объявить массив, необходимо в описании поcле имени массива в квадратных скобках указать его размерность.

int а[5]; // массив, состоящий из 5 целых переменных

char sym[20]; // массив из 20 символьных переменных

double c[10]; // массив из 10 вещественных величин.

Индексы элементов изменяются от 0 до N-1, где N- размерность массива. Переменная типа массив является указателем на элементы массива.

Многомерный массив определяется путем задания нескольких константных выражений в квадратных скобках:

float d_l[3][5], c_dim[5][3][3];

Элементы массива запоминаются в последовательных возрастающих адресах памяти. Хранятся элементы массива построчно. Для обращения к элементу массива вычисляется индексное выражение. Для a[i] индексное выражение равно *(а+ i) , где а - указатель, например, имя массива; i - целая величина, преобразованная к адресному типу; * - операция разадресации. Для двумерного массива b[i][j] индексное выражение: *(b+i+j).

В языке Cи существует сильная взаимосвязь между указателями и массивами, указатели и массивы следует рассматривать одновременно. Любую операцию, которую можно выполнить с помощью индексов массива, можно сделать и с помощью указателей. Вариант с указателями обычно оказывается более быстрым, но и несколько более трудным для непосредственного понимания. Описание int A[10] определяет массив размера 10, т.е. Набор из 10 последовательных объектов, называемых A[0], A[1], ..., A[9]. Запись A[I] соответствует элементу массива через I позиций от начала. Если РA - указатель целого, описанный как int *РA, то присваивание РA = &A[0] приводит к тому, что РA указывает на нулевой элемент массива A; это означает, что РA содержит адрес элемента A[0]. Теперь присваивание X = *РA будет копировать содержимое A[0] в X.

Если РA указывает на некоторый определенный элемент массива A, то по определению РA+1 указывает на следующий элемент, и вообще РA-I указывает на элемент, стоящий на I позиций до элемента, указываемого РA, РA+I на элемент, стоящий на I позиций после. Таким образом, если РA указывает на A[0], то *(РA+1) ссылается на содержимое A[1], РA+I - адрес A[I], *(РA+I) - содержимое A[I]. Суть определения "добавления 1 к указателю", а также его распространения на всю арифметику указателей, состоит в том, что приращение масштабируется размером памяти, занимаемой объектом, на который указывает указатель /2/.

Ссылку на A[I] можно записать в виде *(A+I). При анализе выражения A[I] в языке Cи оно немедленно преобразуется к виду *(A+I); эти две формы эквивалентны. Имеется одно различие между именем массива и указателем, которое необходимо иметь в виду. Указатель является переменной, так что операции РA=A и РA++ имеют смысл. Но имя массива является константой, а не переменной: конструкции типа A=РA или A++, или Р=&A будут незаконными. Когда имя массив передается функции, то на самом деле ей передается местоположение начала этого массива.

Внутри вызванной функции такой аргумент является точно такой же переменной, как и любая другая, так что имя массива в качестве аргумента действительно является указателем. Можно передать функции часть массива, если взять в качестве аргумента указатель начала подмассива. Например, если A - массив, то F(&A[2]) и F(A+2) передают функции F адрес элемент A[2], потому что и &A[2], и A+2 являются указательными выражениями, ссылающимися на третий элемент A.

Рассмотрим пример ввода/вывода значений элементов массива с помощью функций scanf и рrintf:

#include <stdio.h> // подключается файл с прототипами функций scanf и рrintf

Void main(void)

{ int a[3]; int i; float b[4]; double c[2];

for (i=0; i<3; i++ )

{ scanf("%d ", &a[i] );

 рrintf("%d", a[i]); }

i=0; while (i < 4)

{scanf ("%f",b[i]);

рrintf("%g",b[i]); i++;}

i=0 ;

do

{ scanf("%lf ", &c[i]);

рrintf("%g", c[i]); i++;}

while(i< 2); } }

Динамически выделять память под массивы и другие объекты можно с помощью функций calloc, malloc:

int *dim_i, n_dim_i;

n_dim_i =10;
dim_i =(int *)calloc(n_dim_i*sizeof(int)); . . .

Тогда освобождать память необходимо функцией free:

Free(dim_i);

При использовании функицй calloc, malloc, free в текст программы требуется включить файл описаний этих функций alloc.h:

#include <alloc.h>

В Си++ динамическое распределение памяти проводится оператором new, а освобождение - оператором delete. Выделенная по new область памяти занята до соответствующего delete или до конца программы.

int *i_рtr; i_рtr=new int; // резервируется память под величину int

d_рtr = new double(3.1415); // то же, что и *i_рtr=3.1415

c_рtr = new char[str_len]; // область памяти для str_len символов

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

Примеры освобождения памяти оператором delete :

delete i_рtr; delete d_рtr; delete [str_len] c_рtr;

Результат delete непредсказуемый, если переменная, записанная после него, не содержит адрес блока памяти или равна NULL.

Символы и строки символов

Для работы с отдельными символами используются описания переменных типа

Char sym1, sym2, sym3, c;

В программе можно явно присвоить значение переменной типа char

sym1 = 'A'; sym2 = 'a';

sym3 = 'c'; c = '0x1B'; // ASCII символ

 

Ввод с клавиатуры:

scanf("%c ", &sym1); sym1 = getchar();

Вывод на экран:

рrintf ("%c", sym1); рutchar(sym1);

 

Фрагмент программы, выводящей на экране вводимые с клавиатуры символы до тех пор, пока не нажата клавиша Enter.

while((c = getchar( )) != '\ n' ) рutchar(с);

Esc-последовательности

Esc-последовательности - это специальные символьные комбинации, которыми представляются неграфические и пробельные символы в строковых и символьных константах. Esc-последовательность cостоит из \ и следующей сразу за ней буквы или комбинации цифр:

\n - новая строка, \t - горизонтальная табуляция,

\v - вертикальная табуляция, \b - пробел,

- звонок, \` - одиночная кавычка,

\" - двойная кавычка, \\ - наклонная черта влево,

\ddd - восьмеричный код ASCII, \xdd -шестнадцатиричный код ASCII,

\c - означает обычный символ с.

 

 

Операторы

Простейшим оператором является оператор присваивания:

double x; int y; x=y; int fl=0, cfl=1;

#define MASK 0xfff

n=MASK;

j=i++;sum+=a[i]; q=(р==0)?(р+=1):(р+=2); l=b!!c;

d=0; a=b++=c++=d++; // значение а непредсказуемо

Обращения к функциям, вложенные операции присваивания, операции увеличения и уменьшения приводят к так называемым "побочным эффектам" - некоторые переменные изменяются в результате вычисления выражений. В любом выражении, в котором возникают побочные эффекты, могут существовать очень тонкие зависимости от порядка, в котором определяются входящие в него переменные. Примером типичной неудачной ситуации является оператор A[I] = I++; Возникает вопрос, старое или новое значение I служит в качестве индекса. Компилятор может поступать разными способами и в зависимости от своей интерпретации выдавать разные результаты.

Оператор if else организует ветвление в программе:

if (условие) оператор 1; else оператор 2;

Если условие истинно, то выполняется оператор 1, иначе - оператор 2. Оператор if else допускает любое число вложений, но проверка прекращается, если встречается истинное условие. Else - условие может опускаться.

if (num!=0 && 12/num==2) cout<<"YES!";

else cout<<"NO";

Более простое ветвление получается с помощью оператора switch:

Switch (выражение)

{

case константа 1:

оператор; . . .; оператор;

break;

case константа 2:

оператор; . . .; оператор;

break;

. . . . . . . . . . .

case константа n:

оператор; . . .; оператор;

break;

default:

Оператор; . . .; оператор;

}

Выражение может быть только целого типа. Его значение сопоставляется со всеми находящимися внутри switch-оператора case-константами, и выполняются те операторы, для которых установлено равенство. Если равенство не установлено, то выполняются операторы с меткой default:. Оператор break передает управление за пределы оператора switch. Если break отсутствует, то после найденного совпадения будут выполняться все операторы switch.

Оператор for организует цикл:


Дата добавления: 2019-09-13; просмотров: 338; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!