Практикум для изучения дисциплины «Основы программирования»



Pdf көрінісі
бет58/81
Дата08.07.2020
өлшемі1,55 Mb.
#74978
түріПрактикум
1   ...   54   55   56   57   58   59   60   61   ...   81
Байланысты:
А.А. Тюгашев
А.А. Тюгашев, А.А. Тюгашев, А.А. Тюгашев
ЗАМЕЧАНИЕ 
Следует  помнить,  что  объявление  вида  int  *a;  фактически  не  приводит  к 
выделению  памяти  под  массив,  в  отличие  от  int  a[5].  В  связи  с  этим 
необходимо  быть  весьма  осторожным,  чтобы  избежать  трудноуловимых 
ошибок. 
Весьма  интересной  особенностью  Си  является  возможность  создавать 
переменные-указатели на функции и строить затем гибкие программы. На 
самом  деле  это  вполне  естественно  вытекает  из  фон-неймановской 
архитектуры ЭВМ: функция, являющаяся частью программы, находится в 
памяти,  как  и  данные,  соответственно,  ее  начало  имеет  адрес. 
Удивительно,  что  другие  имеративные  языки  не  часто  поддерживают 
данную возможность. Следующий пример содержит иллюстрацию: 
/* Использование функциональной переменной */ 
#include  
 
/* 
первая функция */ 
int fplus(int a,int b) 

  return a+b; 

 
/* 
вторая функция */ 
int fminus(int a,int b) 



115 
 
  return a-b; 

 
 
int main() 

  int a=10,b=10,t; 
  
int (*f)(int,int); /* объявление функциональной переменной */ 
 
  clrscr(); 
  printf("fplus 
адрес %p\n",fplus); 
  printf("fminus 
адрес %p\n",fminus); 
 
  
f=fplus; /* сопоставляем f первую функцию */ 
  t=f(10,10); 
  
printf("Вызываем %p., получаем %d\n",f,t); 
 
  
f=fminus; /* сопоставляем f первую функцию */ 
  t=f(10,10); 
  
printf("Вызываем %p, получаем %d\n",f,t); 
 
  return 0; 

Говоря о функциях в Си, нельзя не отметить такую особенность языка, как 
функции с переменным числом аргументов. Мы уже пользовались ими — 
нетрудно заметить, что printf и scanf принимают произвольное число 
выводимых  или  вводимых  значений.  А  может  ли  программист 
самостоятельно  создать  подобные  функции?  Следующий  пример  это 
иллюстрирует: 
 
/* среднее арифметическое переменного числа аргументов */ 
double f(double n, ...)    /* заголовок с переменным числом 
параметров */ 
{    
    double *p = &n;        /* --
установили на начало списка */ 
    double sum = 0, count = 0;     
 
    
while (*p)         /* пока аргумент не равен нулю */ 
    {  
      
sum+=(*p);         /* cуммируем */ 
      
p++;             /* берем следующий аргумент */ 
      
count++;         /* подсчет количества аргументов */ 


116 
 
    } 
     
    return ((sum)?sum/count:0);    /* 
вычисляем среднее */ 

Есть  одно  обстоятельство,  которое  ограничивает  применение  таких 
функций.  Передача аргумента не того типа, который задумывался, или не 
тем  способом,  который  подразумевался  при  разработке,  приведет  к 
катастрофическим последствиям — компилятор Си ничего не проверяет. 
Для  доступа  к  списку  параметров  в  примере  использован  указатель, 
значением  которого  будет  адрес  последнего  явного  параметра  в  списке. 
Чтобы  перейти  к  адресу  следующего  параметра,  надо  изменить  значение 
этого указателя. Это означает, что программист при разработке функции с 
переменным числом параметров должен отчетливо представлять себе типы 
аргументов,  которые  будет  обрабатывать  функция.  Кроме  того,  способ 
передачи параметров должен быть одинаковым для всех параметров: либо 
все по значению, либо все по указателю. 
Как  в  программе  указать,  каково  фактическое  число  переданных 
параметров? Это можно сделать одним из двух способов: 
 
явно передать среди обязательных параметров количество аргументов; 
 
добавить  в  конец  списка  аргумент  с  уникальным  значением,  по 
которому будет определяться конец списка параметров; 
И  тот,  и  другой  способ  имеют  право  на  жизнь —  все  определяется 
потребностями  задачи  и  вкусами  программиста.  В  примере  использован 
второй способ: последним значением списка параметров считается ноль. 
Еще одной интересной особенностью Си являются смеси и битовые поля
представляющие  собой  особые  разновидности  структур.  Под  полем 
понимается  последовательность  соседних  битов  внутри  одного  целого 
значения,  что  позволяет  обращаться  к  выделенным  частям  одного 
машинного слова. 


Достарыңызбен бөлісу:
1   ...   54   55   56   57   58   59   60   61   ...   81




©engime.org 2024
әкімшілігінің қараңыз

    Басты бет