Главная | Обратная связь | Поможем написать вашу работу!
МегаЛекции

Область видимости и время жизни переменных

По области видимости переменные в Си можно разделить на три группы:

1.Переменная, определенная во всех модулях (файлах) программы. Такая переменная определяется при помощи ключевого слова extern. Эта переменная будет видна во всех точках программы. Такая переменная является глобальной для всей программы.

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

3.Переменная определенная в данной функции. Эта переменная может быть использована только в пределах данной функции. Такую переменную мы будем называть локальной.

По времени жизни все переменные можно разделить на две группы:

1.Переменные живущие в течении работы программы.

2.Переменные уничтожающиеся после выхода из функции.

Глобальные переменные относятся к первому типу по времени жизни. Локальные переменные уничтожаются по выходу из функции. В том случае, когда мы хотим сделать локальную переменную долгоживущей используется слово static. Локальные переменные имеющие такой тип живут начиная с момента первого вызова функции и до конца работы программы. Однако в смысле видимости эти переменные остаются локальными. Запись static int i=0; Означает, что переменная инициализируется нулем при первом входе в функцию, но при последующих входах в функцию ее значение сохраняется в зависимости от тех действий, которые над ней были произведены.

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

И последнее замечание. Динамически выделенная память, где бы вы ее не выделяли живет до тех пор пока вы ее не освободили.

 

Основные операторы

 

Операция присваивания.

Самой общей операцией является присваивание, например, с= a/b. В Си присваивание обозначается знаком равенства=, при этом значение справа от знака равенства присваивается переменной слева. Возможно, применять также последовательные присваивания, например: с = a = b.

Арифметические операторы.

В Си выполняются следующие группы арифметических операций:

1.Бинарные: сложение(+), вычитание(-), умножение(*), деление(/), целочисленное деление(%) (для типа int получение остатка).

2.Унарные: унарный плюс (+), унарный минус (-), адресация (&), косвенная адресация (*), определение размера памяти типа (sizeof).

3.Логические: и (&&), или (!!), не (!=).

4.Отношения:

a)равно (==), не равно(!>);

б) меньше чем (<), больше чем (>), меньше или равно (<=), больше или равно (>=);

5.Приращения (++) и уменьшения (--). Например, i++ обозначает, что i=i+1, а i-- обозначает i=i-1.

6.Побитовые операции - позволяют производить операции над битами.

7.Комбинированные операции. В Турбо-Си существуют сокращения при написании выражений, содержащих многочисленные операции:

a = a + b; сокращается до a += b;

a = a - b; сокращается до a -= b;

a = a * b; сокращается до a *= b;

a = a / b; сокращается до a /= b;

a = a % b; сокращается до a %= b;

8.Адресные операции:

1. Операция определения адреса (&) 2. Операция обращения по адресу (*).

Операция & возвращает адрес данной переменной; если Х является переменной типа int, то &Х является адресом (расположения в памяти) этой переменной. С другой стороны, если msg является указателем на тип char, то *msg является символом, на который указывает msg. Рассмотрим пример:

#include <stdio.h>

main()

{

int X;

char *msg;

X = 6 + 1;

msg = "Привет\n";

printf(" X = %d &X = %p \n",X,&X);

printf("*msg = %c msg = %p \n", *msg, msg);

}

При печати в первой функции печатается два значения: значение X 7 и адрес X (назначаемый компилятором). Во второй функции также печатается два значения: символ, на который указывает msg (П), и значение msg, которое является адресом этого символа (также назначен компилятором).

Старшинство операций в Си соответствует старшинству операций в математике.

Оператор запятая.

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

char X,Y;

(X = Y, Y = getch())

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

Операторы управления.

Оператор If... дает возможность в зависимости от условия выполнять ту или иную ветвь программы. Синтаксис оператора следующий:

If условие выражение1 else выражение2;

Условие должно давать результат в виде логического значения истинности или ложности. Выражение1 будет выполняться если условие истинно. Выражение2 будет выполняться если условие ложно.

Существует сокращенный вариант оператора:

If условие выражение1

Пример. Определить, является ли введенное число днем недели, т.е. входит ли число в диапазон от 1 до 7.

#include <stdio.h>

int A;

main()

{

printf("? ");

scanf("%d",&A);

if ((A < 1) || (A > 7))

printf("Error %d\n",A);

else printf("OK %d\n",A);

}

Выражение условия (A<1) || (A>7) будет давать TRUE, если выполняется A<1 или A>7 - в этом случае выполняется ветка printf('Error ',A);, иначе ветка printf('OK ',A);.

Существует другой вариант записи оператора If... Пример:

#include <stdio.h>

main()

{

int y,t;

printf("? ");

scanf("%d",&t);

y=(t>0)? t*10: t-10; /* if t>0 y=t*10 else y=t-10;*/

printf("OK %d\n",y);

}

В данном варианте вид оператора показан в комментариях.

Оператор switch... case используется в случае, когда необходимо анализировать переменную и в зависимости от ее значения производить те или иные действия. Рассмотрим пример. С клавиатуры вводятся буквы латинского алфавиты. В зависимости от буквы произвести те или иные действия.

#include <stdio.h>

char A;

main()

{

printf("? ");

scanf("%c",&A);

switch (A) {

case 'c': printf(" smoll %c\n",A); break; /* выход из блока */

case 'F':

case 'G': printf(" big %c\n",A);

break;

default: printf("Error %c\n",A);

}

}

В данном примере если введен символ с, то выполняется printf(" smoll %c\n",A);, если вводится заглавные буквы F или G, то выполняется printf(" big %c\n",A);, если не один из рассмотренных символов не вводится, то выполняется printf("Error %c\n",A);.

Для повторения некоторого множества команд несколько раз можно использовать оператор do... while. Рассмотрим пример.

#include <stdio.h>

main()

{

int A;

do {

printf("Zifra? ");

scanf("%d",&A);

printf("Error %d\n",A);

} while (!(A == 9));

printf("OK %d\n",A);

}

С клавиатуры вводится число. Выполняется оператор printf("Error %d\n",A);. Далее идет анализ - равно число 9 или нет, если не равно, снова выполняется тело цикла:

printf("Zifra? ");

scanf("%d",&A);

printf("Error %d\n",A).

Если число равно 9, то выполняется оператор printf("OK %d\n",A); и работа цикла заканчивается.

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

Таким образом, смысл рассматриваемого оператора заключается в следующем: "Выполняй тело цикла до тех пор, пока истинно условие".

Оператор while... в отличие от do... while вначале анализирует условие, а затем выполняет тело цикла.

Пример.

#include <stdio.h>

main()

{

int A;

A = 0;

while (A!= 9)

{

printf("Zifra? ");

scanf("%d",&A);

printf("Error %d\n",A);

}

printf("OK %d\n",A);

}

В данном примере инициализирована переменная A:=0;. Это сделано, потому что вначале идет анализ равна она 9 или нет. Если не равна, то выполняется тело цикла. Смысл рассматриваемого оператора заключается в следующем:

«Пока истинно условие выполняй тело цикла».

Оператор for... используется, когда известно сколько раз необходимо выполнить тело цикла, но этот оператор горазда гибче по сравнению с Паскалем. Рассмотрим пример.

#include <stdio.h>

int          A;

main()

{

for (A = 1; A <= 5; A++) /* A++ означает A=A-1 */

printf("Zifra %d\n",A);

}

В этом примере A хранит состояние счетчика цикла. Первоначально A:=1. Выполняется оператор printf("Zifra %d\n",A). Далее значение A увеличивается на единицу. Идет анализ A<=5 или нет. Если A больше 5, то цикл заканчивает работу. Если нет, то снова выполняется оператор printf("Zifra %d\n",A).

В следующем примере рассмотрим вариант оператора for..., когда начальное значение переменной больше конечного, а переменная во время работы цикла уменьшается на единицу.

#include <stdio.h>

int A;

main()

{

for (A = 5; A >= 1; A--) /* A-- означает A=A-1 */

printf("Zifra %d\n",A);

}

Существует множество модификаций оператора for..., например:

              - пустой оператор - для временной задержки:

                                 for (n=1;n <=10000;n++)

                                ; /* пустой оператор */

              - использование различного шага:

                                 for (n=1;n <=230;n=n+10)

              - изменение переменных:

                                 for (x=2;n*n <=476;n=5*x++)

Рассмотрим пример, в котором инициализируются две переменные и каждая из которых, изменяется после итерации цикла:

#include <stdio.h>

#define f 30

#define n 19

main()

{

int y,t;

for (y = 1,t=f; y<=16; y++,t+=n) /*t+=n означает t=t+n*/ printf(" %3d %7d\n",y,t);

}

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

Оператор goto позволяет передавать управление на любую строку программы. Для этой цели используется метка. Пример.

#include <iostream.h>

#include <stdio.h>

main()

{

char A;

label_1:/* метка */ printf("? \n");

cin>>A;

if (A!= 'y') goto label_1; }

Для прерывания цикла по некоторому условию можно использовать оператор break. Пример.

#include <stdio.h>

#include <iostream.h>

char A;

int I;

main()

{

for (I = 1; I <= 10; I++)

{

printf("? \n");

cin >>A;

i (A == 'y') break;

}

}

Для прерывания итерации цикла и перехода к следующей итерации используется оператор Continue. Пример.

#include <stdio.h>

#include <iostream.h>

char A;

int I;

main()

{

for (I = 1; I <= 10; I++)

{

printf("? \n");

cin >>A;

if (A == 'y') continue;

printf("Работает %c\n",A);

}

}

Для прерывания программы также используются операторы return() и exit().

 

Препроцессор

 

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

Директива #define.

Директива #define может появляться в любом месте программы, а даваемое ею определение имеет силу от места до конца программы.

#include <iostream.h>

#include <stdio.h>

#define TRI 3

#define OTWET TRI*TRI

#define OT printf("ОТВЕТ равен %d.\n",OTWET)

#define jd cin >>C;

main()

{

int C;

OT;

jd;

}

После выполнения программы получится:

ОТВЕТ равен 9

В первой строке программы TRI - это макроопределение и оно равно 3, где 3 - строка замещения.

Во второй строке макроопределение OTWET имеет строку замещения TRI*TRI и т.д. Каждая строка состоит из трех частей. Первой стоит директива #define, далее идет макроопределение. Макроопределение не должно содержать внутри себя пробелы. И, наконец, идет строка (называемая "строкой замещения"), которую представляет макроопределение. Когда препроцессор находит в программе одно из макроопределений, он заменяет его строкой замещения. Этот процесс прохождения от макроопределения до заключительной строки замещения называется "макрорасширением".

Директива #include.

Когда препроцессор "распознает" директиву #include, он ищет следующее за ней имя файла и включает его в текущую программу. Директива бывает в двух видах:

#include<stdio.h> имя файла в угловых скобках

#include "my.h" имя файла в двойных кавычках

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

Директивы: #undef, #ifdef, #else, #endif

Эти директивы позволяют приостановить действие более ранних определений.

Директива #undef отменяет самое последнее определение поименованного макроопределения.

#define TRI 3

#define F 5

#undef TRI /* TRI теперь не определен */

#define F 10 /* F переопределен как 10 */

#undef F /* F снова равен 5 */

#undef F /* F теперь не определен */

Рассмотрим еще пример.

#ifdef OTW

#include "otw.h" /* выполнится, если OTW определен */

#define ST 10

#else

#include "w.h" /* выполнится, если OTW не определен */

#define ST 20

#endif

Директива ifdef сообщает, что если последующий идентификатор OTW определяется препроцессором, то выполняются все последующие директивы вплоть до первого появления #else или #endif. Когда в программе есть #else, то программа от #else до #endif будет выполняться, если идентификатор не определен.

 

Программы. Функции

 

Как мы рассматривали раньше, программа на Си имеет корневой сегмент, начинающийся с директив препроцессора и ключевого слова main.

Далее идет собственно программа, начинающаяся с открывающейся фигурной скобки { и заканчивающаяся закрывающейся фигурной скобкой }.

Часто используемые участки программы выделяются в функции. Каждая функция также начинается с директив препроцессора и имени и скобок { }.

Рассмотрим пример программы рисования лестницы.

#include <stdio.h>

main()

{

printf("|----|\n");

printf("|----|\n");

printf("|----|\n");

}

А теперь напишем эту программу с использованием функции Lestniza.

#include <stdio.h>

Lestniza(void)

{

printf("|----|\n");

}

main()

{

Lestniza();

Lestniza();

Lestniza();

}

Как видно из программы, обращение к функции осуществляется три раза. Для преодоления этого недостатка переработаем программу и введем формальные и фактические аргументы:

#include <stdio.h>

int          C;

Lestniza(int B)/* B - формальный аргумент */

{

int A;

for (A = 1; A <= B; A++)

printf("|----|\n");

}

main()

{

Lestniza(3); /* 3 -фактический аргумент */

}

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

Если в функцию передается несколько параметров, то они должны передаваться в том порядке, в каком записаны в функции.

Рассмотрим функции, возвращающее свое значение на примере возведения числа в квадрат.

#include <stdio.h>

float Kwadrat(float A)

{

return A * A;

}

float     B;

main()

{

printf("? \n");

scanf("%f",&B);

printf("Kwadrat = %8.2f\n",Kwadrat(B));

}

Как видно из примера - имя функции Kwadrat - она вычисляет квадрат числа. В строке printf("Kwadrat = %8.2f\n",Kwadrat(B)); эта функция вызывается - на вход подается значение (введенное число), а в результате получаем результат - квадрат числа, который возвращается в программу по команде return.

Рассмотрим еще один вариант работы с функцией, возвращающей значение без команды return.

#include <stdio.h>

Kwadrat(float A, float *B)

{

*B = A * A;

}

float C, D;

main()

{

printf("? \n");

scanf("%f",&C);

Kwadrat(C,&D);

printf("Kwadrat = %8.2f\n",D);

}


Указатели

 

Указатель - это переменная, содержащая адрес данных, а не их значение. Указатель используется:

1.Для связи независимых структур друг с другом.

2.Для динамического распределения памяти.

3.Для доступа к различным элементам структуры.

Рассмотрим следующую программу:

#include <stdio.h>

main()

{

int Z,*Y;

Y =&Z;

Z = 100;

printf("Прямое значение Z: %d\n", Z);

printf("Значение Z, полученное через указатель: %d\n",*Y);

printf(" Адрес Z через получение адреса: %p\n",&Z);

printf("Адрес Z через указатель: %p\n", Y);

}

В данном примере Y указатель на целую переменную и содержит ее адрес. В свою очередь & позволяет получить адрес по которому размещено значение переменной Z. В этой программе:

- адрес переменной Z присваивается Y;

- целое значение 100 присваивается Z;

- оператор &, позволяет получить адрес,

по которому размещено значение Z.

Результат работы программы:

Прямое значение Z: 100

Значение Z, полученное через указатель: 100

Адрес Z через получение адреса: 85B3:0FDC

Адрес Z через указатель: 85B3:0FDC

Указатели также используются для оптимального распределения памяти.

Рассмотрим пример указателя на число типа char.

#include <stdio.h>

#include <alloc.h>

#include <string.h>

#include <stdlib.h>

#include <process.h>

int main(void)

{

char *str; /* указатель на символьную переменную */

str = (char *)malloc(10);

strcpy(str, "Hello");

printf("String is %s\n", str);

free(str);

return(0);

}

Вначале по команде char *str; создан тип str, который является указателем на переменную типа char(* обозначает "указатель"). По команде str = (char *)malloc(10); выделяем 10 байт памяти под переменную str(типа строка). По команде strcpy(str, "Hello"); осуществляется - "записать в область памяти, на которую указывает str, строку символов "Hello". По команде printf("String is %s\n", str); осуществляется "напечатать на экране то, на что указывает str. Команда free(str); освобождает память, на которую указывает str.

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

#include <stdio.h>

#include <string.h>

#include <alloc.h>

#include <process.h>

struct Student { /* запись Student */

char Fio[30]; /* поле записи Fio */

int Gruppa; /* поле записи Gruppa */

}; /* конец записи */

struct Student *A;

main()

{

if ((A =(Student *) malloc(sizeof(Student))) == NULL)

{

printf("Нет памяти\n");

exit(1);

}

strcpy(A[1].Fio, "Ivanov");

A[1].Gruppa=385;

printf("Fio1 %s\n Gruppa %d\n", A[1].Fio, A[1].Gruppa);

strcpy(A[2].Fio, "Petrow");

A[2].Gruppa=386;

printf("Fio2 %s\n Gruppa %d\n", A[2].Fio, A[2].Gruppa);

free(A);

}

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

Пусть poit является указателем на структуру и что elem элемент, определенный структурным шаблоном. Тогда point->elem определяет элемент, на который выполняется ссылка. Рассмотрим предыдущий пример.

struct Student { /* запись Student */

char Fio[30]; /* поле записи Fio */

int Gruppa; /* поле записи Gruppa */

}; /* конец записи */

Student *poin;

Сейчас к полям структуры мы можем обращаться несколькими способами. Эквивалентные обращения:

Student.Gruppa=236;

poin->Gruppa=236;

Отметим одну важную особенность указателей в Си. Транслятор автоматически учитывает тип указателя в арифметических действиях над ним. Например если i есть указатель на целую (т.е. двухбайтную) переменную, то действие типа i++ означает, что указатель получает приращение не один, а два байта, т.е. будет указывать на следующую переменную или элемент массива. По этой причине указатель можно использовать вместо индексов массива. Например если A - указатель на массив целого типа, то вместо A[i] можно писать *(A+i). Более того, использование указателей вместо индексов позволяет компилятору создавать более компактный и быстрый код.

 

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

 

Указатели также можно использовать в качестве формальных параметров функции. Рассмотрим пример.

Функция swap (обмен) объявляет два формальных параметра x и y, как указатели на данные типа int. Это означает, что функция swap работает с адресами целых переменных (а не с их значениями). Поэтому будут обработаны данные, адреса которых переданы функции во время обращения к ней. Функция main(), вызывает swap.

#include <stdio.h>

swap(int *x, int *y)

{

int wr;

wr = *x; *x = *y; *y =wr;

}

main()

{

int i,j;

i = 100;

j = 200;

printf("Было: i=%d, j=%d\n",i,j);

swap(&i,&j);

printf("Стало: i =%d, j=%d\n",i,j);

}

После выполнения программы значения i и j поменяются местами. Необходимо отметить, что хотя указатели и экономят память, но они используют время процессора горазда больше.

Таким образом, рассмотрены основные элементы языка Си.

Файлы

 

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

Расмотрим сперва режим последовательного доступа.

Ввод-вывода буферизован. Это означает, что программа пишет и читает в буфер; обмен данными между буфером и файлом происходит в случае, если буфер полон, или произошло закрытие файла, или перед выходом из программы.

Рассмотрим пример: считать данные из одного файла и переписать в другой.

#include <stdio.h>

main()

{

FILE *in, *out;

char n1[8], n2[8];

printf("Исходный файл\n");

gets(n1);

printf("Выходной файл\n");

gets(n2);

if ((in = fopen(n1, "rt"))== NULL)

{

printf("Не могу открыть исходный файл\n"); return 1;

}

if ((out = fopen(n2, "wt"))== NULL)

{

printf("Не могу открыть выходной файл\n"); return 1;

}

while (!feof(in))

fputc(fgetc(in), out);

fclose(in);

fclose(out);

}

Строка FILE *in, *out; определяет указатель на два файла. Имя файла м.б. любым- в нашем случае in - исходный файл, out - выходной.

В следующей строке char n1[8], n2[8]; определяем две переменные n1 и n2 для хранения имен файлов. Следующие четыре строки позволяют ввести имена входного и выходного файла и присвоить эти имена переменным n1 и n2. Прежде чем начать работать с файлом он должен быть открыт. Для этого существует функция fopen() в которой первый параметр содержит имя файла, а второй - вид работы, например "rt"– читать файл.

Команда in = fopen(n1, "rt" вызовет открытие файла, запомненного в переменной n1 на чтение, и в программе будет возвращен указатель in на этот файл, которым (указателем) мы и будем пользоваться при чтении символов из файла. Если файл не существует, то значение fp будет NULL, произойдет выполнение fprintf(stderr, "Не могу открыть выходной файл\n"); return 1; и программа завершит работу.

Аналогично работает функция out = fopen(n2, "wt", только теперь out - выходной файл, а вид работы "wt" -запись в файл).

По этой команде создается файл под именем, записанным в переменной n2.

Чтение из файла осуществляется вызовом fgetc(in). Читается один символ из файла, связанного с указателем in.

По команде fputc(fgetc(in), out); считанный символ записывается в файл out. Для чтения информации из всего файла используется конструкция while (!feof(in))

fputc(fgetc(in), out);.

Функция feof(in) возвращает величину, отличную от нуля, если находится в конечной позиции, и ноль - в противном случае. Пока не встретится ноль, данные из исходного файла читаются и записываются в выходной.

Закрытие файла происходит при вызове функции fclose(). Если при этом файл был открыт на запись, происходит вывод содержимого буфера, связанного с этим файлом. Связь между указателем и файлом разрывается.

Аналогично функция fgetc(string,n,fp) читает из файла, связанного с fp, строку и помещает ее в string. Символы читаются, пока не будет получен символ '\n', или пока не исчерпается файл, или пока не будет прочитано (n-1) символов.

Режим прямого доступа более гибок, т.к. позволяет обращаться напрямую к любой записи файла. Минимальной записью для файла прямого доступа является байт. Ниже будет рассмотрен случай файла прямого доступа с записью равной байту. Такие файлы называются двоичными. Файлы прямого доступа незаменимы при написании программ, которые должны работать с большими объемами информации, хранящимися на внешних устройствах. В основе обработке СУБД лежат файлы прямого доступа.

 Кратко изложим основные положения работы с файлами прямого доступа.

1). Каждая запись в файле прямого доступа имеет свой номер. Записи нумерются от 0 до N-1, где N - количество записей в файле. Для двоичного файла N совпадает с длиной файла в байтах. Для открытого файла одна из записей является текущей - говорят, что указатель установлен на данную запись. Перемещать указатель можно при помощи функции lseek.

2). При открытии (или создания файла) указатель автоматически помещается на начало (запись 0). При выполнении операций чтения или записи указатель автоматически перемещается за последнюю считанную (записанную запись) запись.

3). Изменить размер файла (увеличить или урезать) можно при помощи функции chsize. При увеличении размера файла к нему добавляются записи, заполненные кодами 0.

Ниже представлена программа, демонстрирующая работу с файлами.

#include <stdio.h>

#include <io.h>

#include <string.h>

#include <fcntl.h>

#include <SYS\STAT.H>

void main()

{

 int h; /*дескриптор создаваемого файла*/

 char * s="Эта строка будет помещена в файл";

 char buf[7]; /*буфер для чтения из файла*/

 _fmode=O_BINARY; /*работаем с двоичными файлами*/

 if((h=creat("proba.txt",S_IREAD |S_IWRITE))==-1) /*создать файл*/

 {

 printf("Не удалось открыть файл!\n");

 exit(1);

 }

 write(h,s,strlen(s)); /*записать в файл строку s*/

 lseek(h,4,SEEK_SET); /*четвертый байт от начала файла*/

 read(h,buf,6); /*читать слово 'строка' (6 байт) из файла*/

 buf[6]=0; /*отмечаем конец строки*/

 close(h); /*закрыть файл*/

 printf("%s\n",buf); /*печать считанной строки*/

}

Наша программа достаточно полно прокоментирована, поэтому мы приводим достаточно краткие пояснения. Программа создает файл прямого доступа и записывает туда последовательность байт (строку). Далее происходит прямое обращение к подстроке этой строки непосредственно в файле. При разборе текста программы обратим читателей на некоторые моменты:

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

2. При удачном открытии файла ему отводится дескриптор (уникальное число), по которому затем можно к файлу обращаться.

3. Наконец не забывайте, что строка только тогда станет строкой, когда в конце стоит код \0.

В заключении нашего рассмотрения файлов отметим, что наше изложение касалось работы с файлами в среде MS DOS. Работа с файлами в ОС Windows несколько отличается от рассмотренного и основывается на использовании специальных функций API (о программировании в Windows см. ниже).

Дополнительные функции Си

Функции преобразования

Имеется переменная С:

ФУНКЦИЯ ПРОВЕРЯЕТ, ЯВЛЯЕТСЯ ЛИ C

isalpha(c)                      буквой

isdigit(c)                        цифрой

islower(c)                      строчной буквой

isspace(c)                      пустым символом (пробел, табуляция или новая строка)

isupper(c)                     прописной буквой

isalnum(c)  алфавитноцифровым (буква или цифра)

isascii(c)                        кодом ASCII (0-127)

iscntrl(c)                        управляющим символом

ispunct(c)                      знаком пунктуации

toupper(c)  преобразует c в прописную букву

tolower(c)  преобразует c в строчную букву

Пример: преобразует букву A из прописной в строчную a.

#include <stdio.h>

#include <ctype.h>

main()

{

char Z,Y='A';

printf("Было %c\n ",Y);

Z=tolower(Y);

printf("Стало %c\n ",Z);

}

 

Поделиться:





Воспользуйтесь поиском по сайту:



©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...