БИЛЕТ 27.
1) Проверка вида символов и преобразования
Некоторые макросы выполняют проверку символов и преобразования:
isalpha(c) не 0, если "c" алфавитный символ, 0 - если нет.
isupper(c) не 0, если "c" буква верхнего регистра, 0 - если нет.
islower(c) не 0, если "c" буква нижнего регистра, 0 - если нет.
isdigit(c) не 0, если "c" цифра, 0 - если нет.
isspacl(c) не 0, если "c" пробел, табуляция или новая строка, 0 - если нет.
toupper(c) преобразует "c" в букву верхнего регистра.
tolower(c) преобразует "c" в букву нижнего регистра.
2) Указатели и массивы
В языке "C" существует сильная взаимосвязь между указателями и массивами, настолько сильная, что указатели и массивы действительно следует рассматривать одновременно. Любую операцию, которую можно выполнить с помощью индексов массива, можно сделать и с помощью указателей. Вариант с указателями обычно оказывается более быстрым, но и несколько более трудным для непосредственного понимания, по крайней мере для начинающего. Описание int a[10] определяет массив размера 10, т.е. Набор из 10 последовательных объектов, называемых A[0], A[1], ..., A[9]. Запись A[I] соответствует элементу массива через I позиций от начала. Если PA - указатель целого, описанный как INT *PA то присваивание PA = &A[0] приводит к тому, что PA указывает на нулевой элемент массива A; это означает, что PA содержит адрес элемента A[0]. Теперь присваивание X = *PA будет копировать содержимое A[0] в X.
Если PA указывает на некоторый определенный элемент массива A, то по определению PA+1 указывает на следующий элемент, и вообще PA-I указывает на элемент, стоящий на I позиций до элемента, указываемого PA, а PA+I на элемент, стоящий на I позиций после. Таким образом, если PA указывает на A[0], то *(PA+1) ссылается на содержимое A[1], PA+I - адрес A[I], а *(PA+I) -
содержимое A[I].
Эти замечания справедливы независимо от типа переменных в массиве A. Суть определения "добавления 1 к указателю", а также его распространения на всю арифметику указателей, состоит в том, что приращение масштабируется размером памяти, занимаемой объектом, на который указывает указатель. Таким образом, I в PA+I перед прибавлением умножается на размер
объектов, на которые указывает PA.
Очевидно существует очень тесное соответствие между индексацией и арифметикой указателей. в действительности компилятор преобразует ссылку на массив в указатель на начало массива. В результате этого имя массива является указательным выражением. Отсюда вытекает несколько весьма полезных следствий. Так как имя массива является синонимом местоположения его нулевого элемента, то присваивание PA=&A[0] можно записать как PA = A
Еще более удивительным, по крайней мере на первый взгляд, кажется тот факт, что ссылку на A[I] можно записать в виде *(A+I). При анализировании выражения A[I] в языке "C" оно немедленно преобразуется к виду *(A+I); эти две формы совершенно эквивалентны. Если применить операцию & к обеим частям такого соотношения эквивалентности, то мы получим, что &A[I] и A+I тоже идентичны: A+I - адрес I-го элемента от начала A. С другой стороны, если PA является указателем, то в выражениях его можно использовать с индексом: PA[I] идентично *(PA+I). Короче, любое выражение, включающее массивы и индексы, может быть записано через указатели и смещения и
наоборот, причем даже в одном и том же утверждении.
Имеется одно различие между именем массива и указателем,
которое необходимо иметь в виду. указатель является перемен-
ной, так что операции PA=A и PA++ имеют смысл. Но имя массива является константой, а не переменной: конструкции типа A=PA или A++,или P=&A будут незаконными.
Когда имя массива передается функции, то на самом деле ей передается местоположение начала этого массива. Внутри вызванной функции такой аргумент является точно такой же переменной, как и любая другая, так что имя массива в качестве аргумента действительно является указателем, т.е. Переменной, содержащей адрес. мы можем использовать это обстоятельство для написания нового варианта функции STRLEN, вычисляющей длину строки.
STRLEN(S) /* RETURN LENGTH OF STRING S */
CHAR *S;
{ INT N;
FOR (N = 0; *S != '\0'; S++)
N++;
RETURN(N);
}
Операция увеличения S совершенно законна, поскольку эта переменная является указателем; S++ никак не влияет на символьную строку в обратившейся к STRLEN функции, а только увеличивает локальную для функции STRLEN копию адреса. Описания формальных параметров в определении функции в виде
CHAR S[];
CHAR *S;
совершенно эквивалентны; какой вид описания следует предпочесть, определяется в значительной степени тем, какие выражения будут использованы при написании функции. Если функции передается имя массива, то в зависимости от того, что удобнее, можно полагать, что функция оперирует либо с массивом, либо с указателем, и действовать далее соответвующим образом. Можно даже использовать оба вида операций, если это кажется уместным и ясным.
Можно передать функции часть массива, если задать в качестве аргумента указатель начала подмассива. Например, если A - массив, то как
F(&A[2]) как и F(A+2) передают функции F адрес элемента A[2], потому что и &A[2], и A+2 являются указательными выражениями, ссылающимися на третий элемент A. внутри функции F описания аргументов могут присутствовать в виде:
F(ARR)
INT ARR[];
{ ...
}
или
F(ARR)
INT *ARR;
{ ...
}
Что касается функции F, то тот факт, что ее аргумент в действительности ссылается к части большего массива, не имеет для нее никаких последствий.
*************************************27 - 3
Напишите функцию сравнения двух строк.
//sravnenie 2 strok
int strcmp(char *s1, char *s2)
{
int i=0;
while (s1[i] == s2[i] && s1[i] && s2[i])
i++;
if (s1[i]>s2[i])
return 1;
else if(s1[i]<s2[i])
return -1;
else
return 0;
}
*************************************27 - 4
Из заданного натурального числа n удалить все четные цифры.
#include<stdio.h>
#include<conio.h>
#include<math.h>
int n=10;
int k;
int ost,i;
void main()
{
clrscr();
printf("%d\n",n);
k=0;i=0;
while(n!=0)
{
ost=n%10;
n=(n-n%10)/10;
if(ost%2==1)
{
k=k+ost*pow(10,i);
i++;
}
}
printf("%d",k);
getch();
}