Локальные и глобальные переменные. 


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



ЗНАЕТЕ ЛИ ВЫ?

Локальные и глобальные переменные.



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

Переменные, объявленные внутри тела функции, называются локальными.

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

Глобальные переменные объявляются вне тела какой-либо функции и действуют на протяжении выполнения всей программы.

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

Пример 6:

# include <stdio.h> 

# include <conio.h>

int N=5; // глобальная переменная

void vv(void)

{ printf(“ \t N=%d”,N);

N--;

return();

}

void main()

{

int N; // локальная переменная

for (N=0; N<5; N++)

vv();

}

Результат выполнения программы: N=5,N=4,N=3,N=2,N=1.

Обмен данными между функциями.

Возвращаемое значение.

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

Передача одного-единственного значения из вызванной функции в вызвавшую происходит с помощью оператора возврата return. За ключевым словом return может следовать любое выражение.

return ( выражение );

  Оператор return предназначен для двух целей:

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

· Вызывающая функция оповещает, успешно ли решена её подзадача.

Функции, не возвращающие значения, имеют тип возвращаемого значения void.

 

Параметры функции.

Параметры предназначены для передачи некоторых значений в вызываемую функцию из вызывающей. Параметры всегда являются локальными переменными, областью определения которых служит блок функции. В общем случае существуют два стиля передачи параметров функции: вызов функции с передачей значения (call by value) и вызов функции с передачей адресов переменных (call by reference).

· Вызов с передачей значения (call by value) – это простая передача копий переменных вызывающей функции в локальные переменные вызываемой функции, которая не предоставляет вызываемой функции возможности для воздействия на исходные значения переменных (принадлежащие вызывающей функции) в точке возврата, т.е. значения переменных в вызывающей функции не изменяется.

Пример 7:

# include <stdio.h> 

# include <conio.h>

void change (int param)

{printf(“\t Параметр после вызова функции: %d\n”, param);

param=param*param;

printf(“\t Параметр после вычисления: %d\n”,param);

return();

}

void main ()

{ int var=10;

printf(“Переменная var перед вызовом функции:%d\n”,var);

// при вызове функции передаётся значение переменной var

change (var);

printf(“Переменная var после вызова функции:%d\n”,var);

}

Программа выводит следующие результаты:

Переменная var перед вызовом функции: 10

         Параметр после вызова функции: 10

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

Переменная var после вызова функции: 10

 

         
var=10; основная функция
param=10; param=param*param=100;  
 

 

 


После выполнения change значение var не изменится, так как мы изменяли значение копии в стеке.

· Вызов функции с передачей адресов переменных (call by reference) предполагает, что в качестве параметров функции передаются не копии переменных, а копии адресов переменных. Используя указатель, функция осуществляет доступ к нужным ячейкам памяти. Так как известен адрес объекта памяти, то можно изменить его значение. Поэтому при вызове с передачей адресов переменных функция может изменять значения переменных вызывающей программы в точке вызова. Для передачи адреса переменной, которая не является указателем, используется оператор взятия адреса &.

 

Пример 8:

# include <stdio.h> 

# include <conio.h>

void change (int *param) 

{ printf(“\tПараметр после вызова функции: %d\n”,*param);

*param=*param*(*param);/* операция косвенного обращения или разыменования (*) */

 

printf(“\tПараметр после вычисления: %d\n”,*param);

return();

копия адреса var
}

 

 

 


void main ()

{ int var=10;

printf(“Переменная var перед вызовом функции:%d\n”,var);

// вызов функции с передачей адреса переменной var

change (&var);

printf(“Переменная var после вызова функции:%d\n”,var);

}

Программа выводит следующие результаты:

Переменная var перед вызовом функции: 10

         Параметр после вызова функции: 10

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

Переменная var после вызова функции: 100

· В некоторых случаях, хотя в функцию и передаётся указатель, но, тем не менее, нежелательно, чтобы переменная в точке вызова функции меняла значение. Такая ситуация возникает при передаче в функцию указателя на массив или на большие структуры данных. В таких случаях соответствующая переменная может быть защищена с помощью спецификатора const при описании параметра.

Пример 9: определить max и min числа в группе из 4-х чисел. Исходные значения ввести с клавиатуры.

Алгоритм:

1. Функция minmax определяет min и max числа из двух чисел;

2. Ввести 4 числа;

3. Разбить их на пары, в каждой паре найти min и max;

4. Определить наибольший из 2-х max;

5. Определить наименьший из 2-х min;

6. Вывести на печать min и max.

#include <stdio.h>

#include <conio.h>

#include <string.h>

void minmax (int *,int *);

int main()

{ int a,b,c,d;

printf(" Введите 4 числа:");

scanf("%d %d %d %d",&a,&b,&c,&d);

minmax(&a,&b); minmax(&c,&d);

minmax(&a,&c); minmax(&b,&d);

printf("\n max=%d min=%d",a,d);

getch();

}

void minmax (int *x1,int *x2)

{int k;

 if (*x1<*x2) { k=*x1; *x1=*x2; *x2=k;}

 }

Пример 10: вывести на экран изображение пирамиды, высота пирамиды и её цвет ввести с клавиатуры.

#include <stdio.h>

#include <conio.h>

void pir (int m,int c)

{int j,i,k;

 for (j=m; j>=0; j--)

{ textcolor(c+j);

for (i=1; i<j+1; i++)

printf(" ");

k=2*(m-j);

for (i=1; i<k; i++)

cprintf("*");

printf("\n");

}

 }

void main ()

{ int k,n;

printf("n=");

scanf("%d",&n);

printf("цвет=");

scanf("%d",&k);

pir (n,k); // 1-ая пирамида

pir (n+1,k+2); // 2-ая пирамида

getch();

 }

Пример 11: сформировать массив из случайных чисел, найти максимальный элемент каждой строки.

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#include <string.h>

void full(int n,int m,int mas[10][10])

{ int i,j;

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

{

for(j=0; j<m; j++)

   { mas[i][j]=rand()%100;

  printf("%3d",mas[i][j]);

}

printf("\n");

}

}

// нахождение максимального элемента строки

int maxstr(int n,int i,int mas[10][10])

{ int max,j;

max=mas[i][0];   // описание используемого массива

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

if (mas[i][j]>max) max=mas[i][j];

return(max); //возвращается значение максимального элемента

}

//управляющая часть программы

int main()

{ int j,i,n,m,max;

int a[10][10];

srand(time(0));

printf("\n введите размерность массива ");

scanf("%d %d",&n,&m);

full(n,m,a); // n,m-размерность массива, a-адрес массива

printf("\n");

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

{

for(j=0; j<m; j++)

printf("%3d",a[i][j]);

printf("\n");

}

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

{

max=maxstr(m,i,a);

//m-длина строки,i-номер строки

//a-адрес массива (имя массива является его адресом)

printf("\n i=%d max=%d",i,max);

}

getch();

}Библиотечные функции.

Функция

Обозначение функции

Тип

Файл описания

функции аргумента

Абсолютное значение

abs(x) int int <stdlib.h>
fabs(x) double double <math.h>
Косинус cos(x) double double <math.h>
Синус sin(x) double double <math.h>
Округление до большего целого ceil(x) double double <math.h>
Округление до меньшего целого floor(x) double double <math.h>
Степенная функция XY pow(x) double double <math.h>
Степенная функция 10n pow10(x) double int <math.h>
Логарифм натуральный log(x) double double <math.h>
Логарифм десятичный log10(x) double double <math.h>
Корень квадратный sqrt(x) double double <math.h>
Остаток от деления Х на Y fmod(x) double double <math.h>
Генератор случайных чисел в диапазоне от 0 до 32767 rand(x) int   <stdlib.h>

 


Указатели.

Любой объект программы занимает в памяти определённую область. Местоположение объекта в памяти определяется его адресом, для доступа к содержимому объекта служит его имя (идентификатор). Для того, чтобы узнать адрес конкретной переменной используется унарная операция взятия адреса (при этом перед именем переменной ставится знак амперсанта - &). В языке С для хранения адресов используется особый тип переменных - указатели.

  • Указатель -это переменная, в которой хранится адрес объекта данных или функции.

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

Формат объявления переменной – указателя:

  <идентификатор_типа> * <имя_переменной>;

 

  • <идентификатор_типа> определяет тип данных, на который будет ссылаться формируемый указатель. Указатель и адресуемый им объект должны быть одного типа, чтобы операции адресации и разадресации происходили корректно.
  • символ «* » объявляет следующую за ним переменную как указатель и может стоять как после <идентификатора_типа>, так и перед <именем _переменной>.

 

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

int *i_ptr;

char *month[12];   // массив указателей на тип char

char *string_in[20]; // массив из 20 указателей на символы

char *(string_out[20];) // указатель на 20-символьный массив

const int*point;   // указатель на константу-целое число

int *a,*b;         // указатель на тип int

 

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

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

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

Унарный оператор & выдаёт адрес объекта (участка памяти, выделенного на машинном уровне для переменной). Оператор & применяется только к объектам, имеющим имя и размещённым в памяти  (оператор & косвенно заставляет транслятор выделять место в памяти для объявленной ранее переменной).

 

 <указатель>= & <имя_переменной>;

 

Для того чтобы получить (прочитать) значение, записанное в некоторой области, на которую ссылается указатель, используется операция косвенного обращения или разыменования (*).

<имя_переменной> = * <указатель>;

 В y пересылается содержимое адреса, хранимого в a
    (a)

 

Унарные адресные операторы & и * имеют более высокий приоритет, чем арифметические операции.

float a=4.0,*p,z;

p = &z;     // в p -адрес z

*p = 5;     // в z <= 5

a= a + * p + 1; // a =4.0+5+1; p -не изменилось; z =5

 

Унарные арифметические операции ++ или -- имеют одинаковый приоритети при размещении рядом выполняются справа налево.

 

Арифметические операции над указателями.

 

Наименование операции Пример
Сравнение на равенство P 1 == p 2
Сравнение на неравенство P 1!= p 2
Сравнение на меньше P 1 < p 2
Сравнение на меньше или равно P 1 <= p 2
Сравнение на больше P 1 > p 2
Сравнение на больше или равно P 1 >= p 2
Вычисление числа элементов между указателями P 2 - p 1
Вычисление указателя, отстоящего от заданного на определённое в n число элементов P1 + n P1 - n

Инициализация указателей.

Значение указателя перед его использованием обязательно должно быть инициализировано, поскольку объявление указателя позволяет выделить только память для хранения значения указателя, содержимое же этой памяти остаётся неопределённым.

При инициализации указателей возможно использование строковых констант.

 

char *string=”Введите строку”;

 

Под переменную string выделяется память 4 байта. Дополнительно в области констант выделяется память для хранения строки ”Введите строку”, адрес начала которой записывается в string.

Для инициализации указателей допустимо применять операцию взятия адреса &.

int a,b=0; // Указатель на целое инициализируется адресом

int *p_b=&b; // переменной b

char Symbol=’Y’;  //инициализация символьной переменной

char *pSymbol=&Symbol; //определение указателя символ

 

Массивы указателей инициализируются по правилам инициализации массивов.

 

Static char*menu[]={

               ”1. Помощь”,

               "2. Компиляция”,

               "3. Редактирование”,

               "4. Выход в систему”

              };

 

Использование указателей.

Массив указателей фиксированных размеров вводится одним из следующих определений:

тип * <имя_массива > [ размер ];

тип * <имя_массива > [ ]= инициализатор;

тип * <имя_массива > [ размер ]= инициализатор;

размер - константное выражение, вычисляемое в процессе трансляции;

инициализатор – список в фигурных скобках значений типа тип *.

int data[6]; // обычный массив

int *pd[6]; // массив указателей

int *pi[ ]={&data[0],&data[4],&data[2]};

 

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

 

#include <stdio.h>

#include <conio.h>

#define B 6

void main()

{ float array[]={5.0,6.9,2.0,1.0,4.0,8.0};

float *pmin[B];

float *pmax[B];

float *e;

int i,j;

clrscr();

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

pmin[i]=pmax[i]=&array[i];

for (i=0; i<B-1; i++)

for (j=i+1; j<B; j++)

{ if (*pmin[i]<*pmin[j])

  { e=pmin[i];

 pmin[i]=pmin[j];

 pmin[j]=e;

  }

if (*pmax[i]>*pmax[j])

  { e=pmax[i];

 pmax[i]=pmax[j];

 pmax[j]=e;

  }

}

printf("\n по убыванию \n");

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

printf("\t 5.2f",*pmin[i]);

 

printf("\n по возрастанию \n");

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

printf("\t 5.2f",*pmax[i]);

printf("\n исходный массив \n");

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

printf("\t 5.2f",array[i]);

getch();

}

 

Пример использования указателей на массив строк символов.

#include <stdio.h>

#include <conio.h>

void main()

{ char *point[]={"thirteen","fourteen","fifteen","sixteen",

    "seventeen","eigteen","ninteen"};

int i,n;

clrscr();

n=sizeof(point)/sizeof(point[0]);

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

printf(" %s \n",point[i]);

getch();

}

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

 

#include <stdio.h>

#include <conio.h>

void main()

{ char *ps1, *ps2, s1[10],s2[10];

int i,j,*pv,*pm,v[3],mas[2][3];

clrscr();

printf(" введите массив чисел v\n ");

pv=v;

scanf("%d %d %d",pv,pv+1,pv+2);

printf(" введите массив чисел mas\n ");

pm=&mas[0][0]; //инициализация pm адресом 0-ого эл-та массива

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

scanf("%d ",pm+i);

printf(" введите массивы символов s1,s2\n ");

ps1=s1;  // адреса начала массивов s1,s2

ps2=s2;

scanf("%s %s ",ps1,ps2);

// вывод массивов

printf(" массив чисел v\n ");

printf(" %5d %5d %5d\n",*pv,*(pv+1),*(pv+2));

printf(" массив mas\n ");

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

{if(!i%3) printf("\n");

printf("%5d",*(pm+i));

}

printf("\n s1=%s s2=%s ",ps1,ps2);

getch();

}

 

 



Поделиться:


Последнее изменение этой страницы: 2020-12-09; просмотров: 80; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.223.134.29 (0.142 с.)