Язык Си в примерах

Автор: | 05.02.2018

Создание консольного приложения
Структура Си программы
Препроцессорная обработка
Преобразование типа переменных
Программы из 2-х  и более функций
Операции
Массивы
Указатели на переменные
Указатели, как параметры функции
Указатели на другие указатели
Связь между массивами и указателями
Указатели на функции
Динамическое управление памятью
Структура
Примеры деклараций
Тестовые примеры

Создание консольного приложения

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

  • Запустите Visual Studio.NET. Выберите пункт меню File => New => Project (Файл => Создать => Проект) для того чтобы открыть диалог New Project (Новый проект).
  • Выберите пункт Visual C++ в списке Project Types (Типы проектов).
  • Выберите пункт Empty Project (Пустой проект) в списке Templates (Шаблоны).
  • Введите first в качестве названия проекта.
  • Задайте папку, в которой будет храниться проект.
  • Щелкните на ОК для того чтобы закрыть диалог New Project (Создание проекта) и завершить создание нового проекта.
  • Щелкните правой кнопкой на папке Source Files (Исходные файлы) в окне Solution Explorer (Поиск решений). Выберите пункт меню Add => New Item (Добавить => Новый элемент).

  • Выберите в списке Templates (Шаблоны) пункт C++ File (Файл C++). Укажите Ishodnik в качестве названия файла. Введите в окно исходника файла (Ishodnik.cpp) код примера:
#include <iostream>
using namespace std;
// program
void main( )
{
cout << "Welcome to C++ \n";
}
  • Скомпилируйте и запустите проект: Выберите пункт меню Build => Build (Создать => Создать).

Тест пройден успешно! Используйте этот проект для запуска программ, исходные тексты которых приводятся ниже. Изменяйте только текст программы в исходном файле проекта, компилируйте его и осуществляйте запуск.

Структура Си программы

Исходная программа на Си – это совокупность следующих элементов: директив препроцессора, объявлений (деклараций), определений.

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

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

Определения – это описания переменных и функций. Определение переменной в дополнении к ее имени и типу задает начальное значение переменной. Определение функции специфицирует ее структуру, которая представляет собой смесь из объявлений и операторов, которые образуют саму функцию. Определение функции также задает ее формальные параметры и тип возвращаемой величины.

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

Ниже приводятся исходники, на примерах которых в первом приближении рассматриваются специфика структуры и синтаксиса Си-программ.

#include <stdio.h>
#include <conio.h>
void main()
{
int I;
int J;
int C;
printf("How many meters? \n");
scanf("%d",&I);
J=100*I;
printf("%d meters contain %d centimeters \n", I,J);
C=getch();
}

Директива #include добавляет в исходный файл содержимое библиотечного файла (исходный код). Если не указано полное имя, то осуществляется поиск #include-файлов в стандартных директориях. Обрамление имени файла в двойные кавычки (“stdio.h ”) вместо (<stdio.h >) означает, что при поиске файла вначале должна быть просмотрена текущая директория проекта.

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

Функция main служит точкой старта при выполнении программы.

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

В языке C\C++ предусмотрен форматный и бесформатный ввод данных

Строка форматов может включать обычные символы и спецификации, которые начинаются со знака %, за ним следует символ преобразования ( %d целое число; %u целое число без знака; %ld длинное целое число). Например, функция scanf («%d»,&I); позволяет вводить десятичное число с клавиатуры, которое присвоится переменной I. Здесь %d – формат (целое ) для значения переменной I. Операция & возвращает адрес данной переменной. Если I есть переменной типа int, то &I является адресом ее расположения в памяти.

Бесформатный ввод (вывод) данных реализуется для любых типов данных и обеспечивается так называемыми операциями ввода (вывода) в поток. Например:

#include <iostream>
using namespace std;  // для библиотеки указывается пространство имен
main()
{
int i;
cout << "Integer?:";
cin >> i;
cout << " Square of number:" << i*i << "\n";
return 0;
}

Строка программы cout << «Integer?:»; выводит сообщение на экране, посылая его в поток cout. Строка cin >> i; через поток cin переправляет данное с клавиатуры в переменную.

Контрольные задания. Запустите программы из проекта консольного приложения. Если в программах есть ошибки, исправьте их. Прочитайте код программы, используя терминологию программиста.

Препроцессорная обработка

Суть препроцессорной обработки заключается в перестройке перед компиляцией исходника разработчика на основе указанных в коде директив препроцессора (обозначаются символом #). Рассмотрим пример:

#define SIZE 16
#include <stdio.h>
main()
{
char c='A';
#ifdef SIZE
int x=123;
printf("x=%d\n",x);
#else
char x[SIZE]="computer";
printf("x=%s\n",x);
#endif
printf("%c\n",c);
}

Директива вида #define SIZE 16 заменяет в исходнике программы идентификатор SIZE на 16.

Директива #include вставляет в исходник программы исходный код указанного файла.

Условные конструкции #ifdef …#else… #endif  препроцессора перед компиляцией пропускают часть кода программы в зависимости от условия.

Ниже приводится  пример, в котором исходный код, написанный на языке Pascal, при препроцессорной обработке заменяется на Си-исходник:

#include <stdio.h>
 #define then
 #define begin {
 #define end }

main()
 begin                 // {
 int n,x,y,k=0;
 printf("введи n\n");
 scanf("%d",&n);
 for(x=-n;x<=n;x++)
 for(y=-n;y<=n;y++)
 if(2*y-x*x==4)then   // пусто
 begin                //  {
 k=k+1;
 end                  //  }
 if(k==0) then        // пусто
 printf("корней нет\n ");
 end                  //  }


Контрольные задания. Запустите программы из проекта консольного приложения. Если в программах есть ошибки, исправьте их. Прочитайте код программы, используя терминологию программиста.

Преобразование типа переменных

Переменные одного типа могут быть явно преобразованы к другому типу посредством операции приведения типов. Пример:

int i=2;
long l=2;
double d;
float f;
d=(double)i * (double)l;
f=(float)d;


В этом примере величины i,l,d будут явно преобразовываться к указанным в круглых скобках типам.

Программы из 2-х и более функций

Ниже приводится пример программы из 2-х функций.

/*Функция y=t**n*/
int power(int t,int n)
{
int p=1;
while(n!=0)
{
if(n%2 !=0) p=p*t;
n=n/2;
t=t*t;
}
return(p);
}

#include <stdio.h>
main()
{
int a,n;
printf("Input a,n \n");
scanf("%d %d",&a,&n);
printf("%d  to the power of %d = %d",a,n, power(a,n));
}

Точка входа в программу – функция main. Из нее вызывается функция power. Функция определена с 2-я входными  параметрами t и n. При определении функции эти параметры называются формальными.  При вызове функции она получает фактические параметры a и n. Значение, вычисляемое функцией power, передается в main с помощью оператора return(p).

Функция power должна быть определена или объявлена до ее вызова в main. Что такое объявление функции? До сих пор мы сталкивались только с объявлением переменных. Объявление функции имеет вид:

int power(int t,int n);

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

Контрольные задания. Прочитайте программу. Запустите программу из проекта консольного приложения. Поменяйте местами определения функций power и main и выполните все необходимое для запуска программы.

Ниже приводится пример программы из 2-х функций, в которой делается неудачная попытка поменять значение переменных.

void obmen(int x,int y) // Неверное решение
{
int t;
t=x;
x=y;
y=t;
}

#include <stdio.h>
void main()
{
int a,b;
a=3; b=7;
obmen(a, b);
printf("a=%d b=%d \n",a,b);
}

Почему неверное решение? Вызванная функция копирует значения фактических параметров в локальные переменные, но обратно обновленные значения не возвращает.

Контрольное задание. Запустите программу. Прочитайте программный код.

В определении следующей функции видим, что вместо входных параметров используется ключевое слово void.

void voutput(void) {
int it = 12345;
double du;
du = sqrt(it);
printf("Kvadratny koren chisla %d raven %f \n", it, du);
}


В соответствии со стандартом ANSI С ключевое слово void применяется для явного указания на отсутствие аргументов функции. Указывать слово void не обязательно, хотя это широко используется.

Операции

Ниже рассмотрены специфические операции языка Си.

В примере:

max = (d<=b) ? b : d;

сокращенная форма оператора if — then — else, переменной max присваивается максимальное значение переменных d и b.

Присваивание x*=y+1 фактически означает x=x*(y+1), а не x=x*y+1.

Если считать, что значение n равно 5, то переменная m в выражении m=++n, будет иметь значение 6, а в выражение m=n++ переменная m равна 5, в том и этом случае переменная n будет равняться 6. Первый пример в точности соответствует следующей последовательности операторов n=n+1; m=n; а второй последовательности m=n; n=n+1. В первом примере на результате сказывается приоритетность операций, операция  = приоритетнее операции ++.

#include <stdio.h>
int another_function(int x) { return ! ((~(~0U>>1)|x)&x -1) ;}
int main(void)
{
int i;
for (i = 0; i < 256; ++i)
printf("%3d: %d\n", i, another_function(i));
return 0;
}
& — поразрядное И
>> — сдвиг вправо
| — поразрядное ИЛИ
<< — сдвиг влево
~ — инверсия
! — логическое «НЕ»
Целая константа- это десятичное (10), восьмеричное (012) или шестнадцатеричное число (0Xa или 0xA). Константа без суффикса u или U считается знаковой.

В выражениях с несколькими операциями более приоритетные операции вычисляются первыми.
Операция ~ (инвертирует битовое представление числа) более приоритетна операции >>( побитовый сдвиг вправо на число позиций, специфицированных вторым операндом).
Операция ~ более приоритетная операции | (побитовое включающее ИЛИ).

Операция (минус) более приоритетная операции & (побитовое И).
операции & (побитовое И) или может это операция адресации? (по контексту)
Если считать, что значение n равно 5, то переменная m в выражении m=++n будет иметь значение 6, а в выражение m=n++ переменная m равна 5

Массивы

Массив – это совокупность данных одного типа. В случае многомерных массивов показывают столько пар скобок, какова размерность массива, например int a[2][5];

Обращение к некоторому элементу массива a[1][3], a[0][k+2]. Индексы массива в Си всегда начинаются с 0, а не с 1,

Двумерный массив можно инициировать так: int a [2][5] = {{3,4,0,1,2},{6,5,1,4,9}};

В языке Си отсутствует возможность динамически выделять память под массивы традиционным способом, однако для массива типа char делается исключение:

/*длина строки*/
int length(char s[])
{
int i=0;
while(s[i]!='\0')
i++;
return(i);
}

#include <stdio.h>
void main()
{
static char str[] ="TEXT";
printf("%d \n",length(str));
}

Любая символьная константа, например «TEXT», представляет собой массив символов. Если длина строки в квадратных скобках опущена, то она определяется автоматически, по количеству присваиваемых символов. Завершается такой массив символом «\0».

Размер массива можно задать либо в квадратных скобках char str [5], либо указывая список начальных значений при инициализации массива char str[] =»TEXT». В процессе инициализации массива, для которого не задан размер, компилятор автоматически создаст массив такого размера, чтобы вместить все указанные элементы.

Контрольное задание. Запустите программу. Прочитайте программный код.

Указатели на переменные

До сих пор все было относительно просто. Сложности понимания программ на языке C обычно начинаются с указателей. Рассмотрим специфику указателей на простейших примерах.

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

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

int x=1, y=2, z[ 10];
int *uk; // uk- указатель на int
uk =&x; // теперь uk указывает на x
y = *uk; // y теперь равен 1
*uk = 0; // х теперь равен 0
uk = &z[0]; // теперь uk указывает на z[0 ]

Обратите внимание. Звездочка (*) около указателя есть в двух случаях — при декларации и раскрытии значения по указателю. Если указателю присваивается адрес, она отсутствует

Контрольный вопросы. Какое значение переменной y после выполнения кода?

При объявлении указателя операционная система выделяет память (4-е байта для 32 разрядной системы) только лишь для хранения самого указателя, а не под то, на что он будет указывать. Тогда зачем в декларации указателя описывать тип объекта?

Ответ. При объявлении типа указателя с ним можно выполнять операции сложения и вычитания, поскольку тип указателя определяет количество байт, на которое изменяется значение указателя. Например, при выполнении операции ++ (инкремент) значение указателя изменяется не на 1 (единицу), а на количество байт, отводимых под переменную указанного типа:

int *pi;
double *pf;
int an_integer;
double a_real;
pi = &an_integer;
pf = &a_real;
pi++;      // значение изменилось на 4
pf++;      // значение изменилось на 8

Контрольное задание. Создайте программу, которая обеспечивает форматный вывод адресов указателей до операции ++ и после нее.

Допускается объявлять указатель неопределенного типа (void),  но перед выполнением арифметических операций его нужно явно переопределить:

double nomer;
void *addres;
addres = & nomer;
(double *)addres ++;

Указатели, как параметры функции

Как выше было уже отмечено, нельзя обновить значения входящих параметров, поскольку функция работает с копиями фактических переменных:

/* Неправильное использование параметров */
void change (int x, int y)
{ int k=x;
x=y;
y=k;
}

Однако, если в качестве параметра передать указатель на некоторую переменную, то можно изменить значение этой переменной. Ранее мы могли возвращать результат работы функции только через return.

/* Правильное использование параметров */
void change (int *x, int *y)
{ int k=*x;
*x=*y;
*y=k;
}

При вызове такой функции в качестве фактических параметров используются не значения переменных, а их адреса:

change (&a,&b);


В этом примере входные переменные возвращаются обновленными. Как объяснить этот феномен? Дело в том, что функция использует копии указателей на те же переменные.  А копии обладают теми же возможностями раскрытия значения по указателю, что и оригиналы.

Указатели на другие указатели

В C/C++ можно создавать указатели на другие указатели, которые, в свою очередь, содержат адреса реальных переменных

int ivalue = 10;
int *pi;
int **ppi;
pi = &ivalue;
ppi = &pi;

Связь между массивами и указателями

Между указателями и массивами существует тесная связь. Например, когда объявляется массив в виде int array[25], то этим определяется не только выделение памяти для двадцати пяти элементов массива, но и значение адреса первого по счету (нулевого) элемента массива, которое хранится в переменной с именем array.

int array[25];
int *ptr;
ptr=array;

Последний рядок можно записать в эквивалентной форме ptr = &array[0]. Получается, что определяя массив, мы автоматически получаем указатель. Это не совсем так, поскольку значение имени массива array нельзя изменить (имя массива-указателя это константа), а значения указателя ptr (это переменная) можно:

ptr=ptr + 1;

Объявление двумерного массива arr[4][3] порождает в программе три разных объекта: указатель с идентификатором arr, безымянный массив из четырех указателей и безымянный массив из двенадцати чисел типа.

Здесь уточним. Массив и четырех указателей есть виртуальным. Реальный только массив из 12 чисел, которые последовательно расположены в памяти — в ряду слева направо, по рядам сверху вниз. Виртуальный массив служит лишь для описания последовательности доступа к реальным элементам массива – от указателей на ряды к элементам ряда.

Для доступа к элементам массива может быть использовано индексное выражение в форме arr[1][2] или эквивалентные ей адресные выражения (*(arr+1))[2] и *(*(arr+1)+2).

Контрольное задание. Прочитайте код *(*(arr+1)+2), докажите, что он эквивалентный arr[1][2].

Указатели на функции

Рассмотрим теперь указатели на функции. Синтаксически имя функции является адресом начала тела функции. Точно, как и имя массива есть адресом первого элемента массива. Это значит, что функция может быть вызвана и через указатель на функцию. Пример:

double (*fun1)(int x, int y); /* объявление указателя на функцию */
double fun2(int k, int l); /* объявление функции */
fun1=fun2;                /* инициализация указателя на функцию */
(*fun1)(2,7);           /* обращение к функции через указатель */

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

Объявляется указатель fun1 на функцию, которая содержит 2 параметра типа int и возвращает значение типа  double

Вызов функции происходит через знак  раскрытия значения по указателю (*) .

Указатель на функцию может быть передан в качестве параметра функции. Ниже приведен пример, в котором один из параметров функции proiz есть указатель на функцию.

#include <iostream>
using namespace std;
#include <stdio.h>
#include <math.h>

double proiz(double x, double dx, double (*f)(double x) );
double fun(double z);

int main()
{
double x; /* точка вычисления производной */
double dx; /* приращение */
double z; /* значение производной */
cin >> x; /* ввод значения x */
cin >> dx; /* ввод значения dx */
z=proiz(x,dx,fun); /* вызов функции */
cout << z << "\n"; /* печать значения производной */
return 0;
}

double proiz(double x,double dx, double (*f)(double z) )
{ /* функция, вычисляющая производную */
double xk,xk1,pr;
xk= (*f) (x);
xk1= (*f) (x+dx);
pr=(xk1/xk-1e0)*xk/dx; //1e0 - константа с плавающей точкой
return pr;
}

double fun( double z)
{ /* функция от которой вычисляется производная */
return (cos(z));
}

Функция proiz вычисляет производную от функции cos(x) опосредовано через функцию fun.

Для вычисления производной от какой-либо другой функции можно изменить тело функции fun или использовать при вызове функции proiz имя другой функции. В частности, для вычисления производной от функции cos(x) можно вызвать функцию proiz в форме

z=proiz(x,dx,cos);

 Контрольное задания. Прочитайте программный код. Запустите программу для вычисления производной от функции sin(x) в форме z=proiz(x,dx,sin); .

Динамическое управление памятью

В языке Си отсутствует возможность динамически управлять памятью под массивы через индексное выражение в форме arr[] []. Такая возможность реализуется через указатели, функции malloc, calloc и free.

Пример программы 1:

#include <stdio.h>
#include <malloc.h>
void main( void )
{
long *buffer;
// размер памяти под массив из 40 элементов типа long
buffer = (long *)calloc( 40, sizeof( long ) );
if( buffer != NULL )
printf( "Allocated 40 long integers\n" );
else
printf( "Can't allocate memory\n" );
free( buffer );
}

Пример программы 2:

/*копия строки*/
#include <stdio.h>
#include <malloc.h>
void copy(char *s1, char *s2)
{
while((*s2=*s1)!='\0')
{
s2++;s1++;
}
}

void main()
{
char *str1= "Hello";
char *str2;
// размер памяти под массив из 7 элементов типа char
str2 = (char *)malloc(sizeof(char)*7);
copy(str1, str2);
printf("%s \n",str2);
}


Функции malloc и calloc возвращают указатель на динамически запрашиваемую ими область памяти. Функция free (p) освобождает область памяти, на которую ссылается указатель. Указатель, возвращаемый функциями malloc и calloc, имеет тип void. К нему должна быть применена операция явного приведения к соответствующему типу.

Контрольное задание. Прочитайте программный код. Запустите программу 2.

Структура

Структура – это совокупность логически связанных переменных, сгруппированных под одним именем для удобства дальнейшей обработки. В отличие от массива, который является однородным объектом, структура может быть неоднородной (различные типы переменных).

Описание:

struct anketa
{
int tab_nom;
char fio[30];
char data[10];
int pol;
char adres[40];
float summa;
};

Объявление:

struct anketa a0,a1,a2;

Инициализация (определение):

struct anketa a0 = { 1024, "Макагон В.М", "10.01.1943",0 , "Одесса, Варневская, 23/99", 175.00};

Обращение:

a1.fio ="Макагон В.М";

Структуры нельзя копировать или присваивать как единое целое; их нельзя передавать в функцию или получить оттуда целиком. Однако, существует возможность обойти это ограничение, используя в качестве аргумента указатель на структуру.

Объявление:

struct anketa *uk;

Обращение:

uk-> fio ="Макагон В.М";
(*uk). fio ="Макагон В.М";

Скобки обязательны, так как приоритет операции выделения элемента «.» выше чем у «*».

Примеры деклараций

В первом примере объявляется функция, поименованная add, которая требует два аргумента типа int и возвращает величину типа int.

int add(int, int); /* Example 1 */

Во втором примере объявляется функция, поименованная calc, которая возвращает величину типа double. Список типов аргументов не задан.

double calc(); /* Example 2 */

В третьем примере объявляется функция, поименованная strfind, которая возвращает указатель на величину типа char. Функция требует, по крайней мере, один аргумент указатель на величину типа char. Список типов аргументов заканчивается запятой с многоточием, обозначающим, что функция может потребовать большее число аргументов.

char *strfind(char *,...); /* Example 3 */

В четвертом примере объявляется функция с типом возврата void (нет возвращаемой величины). Список типов аргументов также void, означающий отсутствие аргументов для этой функции.

void draf(void); /* Example 4 */

В пятом примере объявлена функция prt, которая требует аргумент- указатель любого типа, и которая возвращает величину типа int. Любой указатель p или q могли бы быть использованы как аргументы функции без выдачи при этом предупреждающего сообщения.

char *p; /* Example 5*/
short *q;
int prt(void *);

В следующих 2-х примерах показывается, каким образом круглые скобки могут поменять смысл объявлений.

  • long *var(long,long); – функция, возвращающая указатель на величину типа long. В этом примере модификатор функции имеет более высокий приоритет, чем модификатор указателя, так что переменная var объявляется функцией, возвращающей указатель на величину типа long. Функция объявлена с двумя аргументами типа long. 
  • long (*var) (long,long); – указатель на функцию, возвращающую величину типа long. Этот пример похож на второй. Скобки задают более высокий приоритет модификатору указателя, и поэтому переменная var объявляется как указатель на функцию с двумя аргументами типа long и возвращающую величину типа long.

Тестовые примеры

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

Пример 1:

#include <stdio.h>
#include "conio.h"
void main()
{
int I;
int J;
int C;
printf("How many meters? \n");
scanf("%d",&I);
J=100*I;
printf(" %d meters contain %d centimeters \n", I,J);
C=getch();
}

Пример 2:

#include <iostream>
using namespace std;
main()
{
int i;
cout << "Integer?:";
cin >> i;
cout << " Square of number:" << i*i << "\n";
return 0;
}

Пример 3:

#define SIZE 16
#include <stdio.h>
main()
{
char c='A';
#ifdef SIZE
int x=123;
printf("x=%d\n",x);
#else
static char x[SIZE]="computer";
printf("x=%s\n",x);
#endif
printf("%c\n",c);
}

Пример 4:

#include <stdio.h>
#define then
#define begin {
#define end }
main()
begin
int n,x,y,k=0;
printf("Vvedi n\n");scanf("%d",&n);
for(x=-n;x<=n;x++)
for(y=-n;y<=n;y++)
if(2*y-x*x==4)then
begin
k=k+1;
printf("x=%d, y=%d\n",x,y);
end
if(k==0) then
printf("kornei net\n ");
end

Пример 5:

int i=2;
long l=2;
double d;
float f;
d=(double)i * (double)l;
f=(float)d;

Пример 6:

/*Функция y=t**n*/
int power(int t,int n)
//int t,n;
{
int p=1;
while(n!=0)
{
if(n%2 !=0) p=p*t;
n=n/2;
t=t*t;
}
return(p);
}

#include <stdio.h>
main()
{
int a,n;
printf("Введи a,n \n");
scanf("%d %d",&a,&n);
printf("%d v stepeni %d = %d",a,n, power(a,n));
}

Пример 7:

void obmen(int x,int y)
{
int t;
t=x;
x=y;
y=t;
}

#include <stdio.h>
void main()
{
int a,b;
a=3; b=7;
obmen(a, b);
printf("a=%d b=%d \n",a,b);
}

Пример 8:

void voutput(void) {
int it = 12345;
double du;
du = sqrt(it);
printf("kvadratny koren chisla %d raven %f \n", it, du);
}

Пример 9:

x*=y+1

выберите равноценный аналог верхнего выражения:

x=x*(y+1)
x=x*y+1

Пример 10:

max = (d<=b) ? b : d;

Пример 11:

#include <stdio.h>
int another_function(int x) { return ! ((~(~0U>>1)|x)&x -1) ;}
int main(void)
{
int i;
for (i = 0; i < 256; ++i)
printf("%3d: %d\n", i, another_function(i));
return 0;
}

Пример 12:

Прочитать целые константы:

10
012
0Xa
0xAU

Пример 13:

Если n равно 5, то m

m=++n
m=n++

Пример 14:

/*длина строки*/
int length(char s[])
{
int i=0;
while(s[i]!='\0')
i++;
return(i);
}

#include <stdio.h>
void main()
{
static char str[ ] ="TEXT";
printf("%d \n",length(str));
}

Пример 15:

char str[] ="TEXT"
char code[3] = "abcd"

Пример 16:

int x=1, y=2, z[ 10];
int *uk;
uk =&x;
y = *uk;
*uk = 0;
uk = &z[0];

Пример 17:

int *pi;
float *pf;
int an_integer;
float a_real;
pi = &an_integer;
pf = &a_real;
pi++;
pf++;

Пример 18:

double nomer;
void *addres;
addres = & nomer;
(double *)addres ++;

Пример 19:

void change (int x, int y)
{ int k=x;
x=y;
y=k;
}

Пример 20:

void change (int *x, int *y)
{ int k=*x;
*x=*y;
*y=k;
}

Пример 21:

int array[25];
int *ptr;
ptr=array;
ptr=ptr + 1;

Пример 22:

int arr[1][2]
int a;
a = *(*(arr+1)+2)

Пример 23:

int (*fun)(int x, int *y);

Пример 24:

int *fun (int x, int *y);

Пример 25:

double (*fun1)(int x, int y);
double fun2(int k, int l);
fun1=fun2;
(*fun1)(2,7);

Пример 26:

#include <iostream.h>
#include <stdio.h>
#include <math.h>
double proiz(double x, double dx, double (*f)(double x) );
double fun(double z);

int main()
{
double x; /* точка вычисления производной */
double dx; /* приращение */
double z; /* значение производной */
cin >> x;
cin >> dx;
z=proiz(x,dx,fun);
cout << z << "\n";
return 0;
}

double proiz(double x,double dx, double (*f)(double z) )
{ /* функция вычисляющая производную */
double xk,xk1,pr;
xk= (*f) (x);
xk1= (*f) (x+dx);
pr=(xk1/xk-1e0)*xk/dx; //1e0 - константа с плавающей точкой
return pr;
}

double fun( double z) {return (cos(z)); }

Пример 27:

#include <stdio.h>
#include <malloc.h>

void main( void )
{
long *buffer;
buffer = (long *)calloc( 40, sizeof( long ) );
if( buffer != NULL )
printf( "Allocated 40 long integers\n" );
else
printf( "Can't allocate memory\n" );
free( buffer );
}

Пример 28:

#include <stdio.h>
#include <malloc.h>

void copy(char *s1, char *s2)
{
while((*s2=*s1)!='\0')
{
s2++;s1++;
}
}
void main()
{
char *str1= "Hello";
char *str2;
str2 = (char *)malloc(sizeof(char)*7);
copy(str1, str2);
printf("%s \n",str2);
}

Пример 29:

struct anketa
{
int tab_nom;
char fio[30];
char data[10];
int pol;
char adres[40];
float summa;
};

struct anketa a0,a1,a2;
struct anketa a0 = { 1024, "MAKAGON V.M.", "10.01.1943",0 , "Odessa, Varnevskaja, 23/99", 175.00};
a1. fio ="MAKAGON V.M."
struct anketa *uk;
uk->fio ="MAKAGON V.M.",
(*uk).fio ="MAKAGON V.M."

Пример 30:

int add(int, int);

Пример 31:

char *strfind(char *,...);

Пример 32:

void draf(void);

Пример 33:

int prt(void*);

Пример 34:

long *var(long,long);

Пример 35:

long (*var) (long,long);

 

Автор: Николай Свирневский

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *