Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Язык Си для начинающих! С нуля! Учим быстро и просто!


 
Автор выпуска Олег Маркатов
E-mail: markatof@mail.ru

 Здравствуйте, уважаемые читатели!



Рекомендуемая электронная литература
Литература в помощь изучающим язык C и C++
1) В небольшом архиве Вы найдете полезную информацию и тексты программ к лекционному курсу для изучающих алгоритмические языки программирования Си и С++
ссылка: http://aiv.spb.ru/files/i1.php cтоимость: $0.3 (оплата с мобильника) 
2) Электронное пособие ЯЗЫК ПРОГРАММИРОВАНИЯ Си
Электронное пособие «ЯЗЫК ПРОГРАММИРОВАНИЯ Си в вопросах и ответах» 
ссылка: http://aiv.spb.ru/files/i2.php
cтоимость  $1.0 (оплата с мобильника)

         В этом выпуске рассылки я покажу на конкретных примерах как можно выделять память под динамические переменные и работать с указателями.
Определение. УКАЗАТЕЛЬ -  это переменная, содержащая адрес некоторых данных, а не их значение. Зачем это нужно? Использование  указателей  позволит вам создавать новые переменные в процессе выполнения программы.   Си  позволяет вашей программе   запрашивать некоторое количество памяти (в байтах), возвращая адреса, которые можно запомнить в указателе. Этот прием известен как ДИНАМИЧЕСКОЕ РАСПРЕДЕЛЕНИЕ; используя его, ваша программа может приспосабливаться к любому объему  памяти,   в зависимости от  того,  как много (или мало)  памяти доступно вашему компьютеру.
        Вы можете использовать указатели  для  доступа  к различным элементам  структур данных,  таким как массивы,  строки или структуры.

iptr = (int *) malloc(sizeof(int));

  • 1) выражение  sizeof(int)   возвращает  количество байтов, требуемое для хранения переменной типа int; для  компилятора Турбо Си,  работающего на IBM PC, это возвращаемое значение равно 2.
  • 2) функция malloc(num)  резервирует  num  последовательных байтов доступной (свободной) памяти в компьютере, а затем возвращает начальный адрес размещения в памяти этой  последовательности байтов.
  • 3) выражение (int *)  указывает,  что этот начальный адрес  указатель на данные типа int. Выражение такого вида известно     как  выражение  приведения  типа  (type casting). В  данном случае Турбо Си не  требует  обязательного его применения.
(В качестве дополнительной литературы рекомендую книгу В.В. Подбельский, С.С. Фомин Программирование на языке Си


Указатели бывают:
  • 1) указатели переменных
  • 2) адресные указатели


         Указатель - это переменная, значением которой является ссылка на другой объект. Указатели делятся на указатели переменных и  адресные  указатели, которые локализируют объемы памяти. Адресные указатели типа (void *)  отличаются от других указателей тем, что существует возможность выполнения преобразования указывающего данного, используя оператор указания, записываемый с помощью знака & (амперсенд). Предполагается что если exz - имя переменной, то &exz - указатель этой переменной. Из этого правила существует только одно исключение, если exz - переменная,  которая является именем массива, то принимается, что уже эта сама запись указывает на первый элемент массива. Поскольку образование массивов часто производится с помощью  указателей, надо помнить, что если vec - произвольный вектор, то имя vek[i] трактуется точно так, как и выражение *(vec+i) ,  которое также может быть принято за имя элемента.
Пример - значение переменной и ее адрес

#include <stdio.h> 
#include <conio.h> 
main() 
{ float a=7.5; 
  int   i=3; 
char  c='a'; 
clrscr(); 
printf("\n Адрес (&) и значение переменной"); 
printf("\n        &a=%d a=%f",&a,a);              printf("\n        &i=%d a=%d",&i,i); 
printf("\n        &c=%d a=%c",&c,c); 
}


Прямое указание


#include <stdio.h> 
main() 
{ /* Прямое указание */ 
int   i=10; 
int   *p=&i; 
printf("\n i=%d &i=%d *p=%d p=%d",i,&i,*p,p); 
*p=*p+3; 
printf("\n i=%d &i=%d *p=%d p=%d",i,&i,*p,p); 
}


i=10 &i=-36 *p=10 p=-36
i=13 &i=-36 *p=13 p=-36

Косвенное указание
#include <stdio.h> 
main() 
{ /* Косвенное указание */ 
int   i=10; 
int   *ref=&i; 
int   **p=&ref; 
printf("\n **p=%d",**p); 
}

**p=10


ВЫДЕЛЕНИЕ ПАМЯТИ


#include <alloc.h> 
#include <stdio.h> 
main() 
{ int *iptr; 
  iptr = (int *)malloc(sizeof(int)); 
  *iptr = 421; 
  printf("Содержимое iptr: %p\n", iptr); 
  printf("Адресуемое значение: %d\n",*iptr); 
  }


Содержимое iptr: 065A
Адресуемое значение: 421

     calloc: allocates main memory   - отвечает за выделение памяти, в которой можно разместить динамические переменные. 

void *calloc(
size_t nelem,  size_t elsize);

Prototypes in stdlib.h alloc.h 
Allocates space for nelem items of elsize  bytes each and stores zero in the area. 
Returns a pointer to the newly allocated   block or NULL if not enough space exists. 

See also      malloc


 Программа,  определяет два  двумерных массива, а затем выполняет их матричное умножение


#include <stdio.h> 
/* Рассмотрим программу,  которая определяет два  дву- 
мерных массива, а затем выполняет их матричное умножение: */ 
main(){ 
int a[3][4] = {{ 5,  3, -21, 42}, 
{44, 15,   0,  6}, {97 , 6,  81,  2}}; 
int b[4][2] = {{22,7},{97, -53},{45,   0}, {72,   1} }; 
int c[3][2],i,j,k; 
for (i=0; i<3; i++) { 
for (j=0; j<2; j++) { 
c[i][j] = 0; 
for (k=0; k<4; k++) 
c[i][j]+= a[i][k] * b[k][j]; 
} } 
  for (i=0; i<3; i++) { 
  for (j=0; j<2; j++) 
printf("c[%d][%d] = %d ",i,j,c[i][j]); printf("\n"); } }


c[0][0] = 2480 c[0][1] = -82
c[1][0] = 2855 c[1][1] = -481
c[2][0] = 6505 c[2][1] = 363



#include <stdio.h>
main()
{ float a=123.45678;
printf("\n a=%f a=%+3.1f  a=%.5f  a=%.10f",a,a,a,a);
}
a=123.456779 a=+123.5  a=123.45678  a=123.4567794800 

Эквивалентные  формы записей
vec[i]
*(vec+i)
----------------------------------------
short int arr[2][3];
arr[i][j]
*(*(arr+i)+j)
----------------------------------------

arr[0][0]
**arr



 

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



#include<stdio.h> 
int arr[2][2]; 
int (*ref)[2]; 
main() 
{arr[1][1]=13; 
arr[1][2]=14; 
ref=arr+1; 
printf("\n %d",(*ref)[1]); 
printf("\n %d",(*ref)[2]); 

----------------------------------------
13
14

#include<stdio.h> 
#include<alloc.h> 
main() 
{float *ref; 
 int n; 
printf("\nВведите N="); 
scanf("%d",&n); 
printf("\n3)= %d",coreleft()); 
printf("\n1)= %u",coreleft()); 
ref=calloc(n,sizeof(float)); 
printf("\n2)= %u",coreleft()); 
free(ref); 
printf("\n3)= %u",coreleft()); 
printf("\n3)= %d",coreleft()); 
}
----------------------
Введите N=200 
3)= -2874
1)= 62662
2)= 61854
3)= 62662
3)= -2874



 


Найти S сумму всех n элементов масcива ref.


 




#include<stdio.h> 
#include<alloc.h> 
main() 
{float *ref,tmp,s=0; 
 int n,i; 
printf("\nВведите N="); 
scanf("%d",&n); 
ref=calloc(n,sizeof(float)); 
for (i=0;i<n;i++){ 
scanf("%f",&tmp); 
ref[i]=tmp; 
s=s+ref[i];} 
free(ref); 
printf("\n S=%f",s); 
}


 

Программа, иллюстрирующая СВЯЗЬ  ПАРАМЕТРОВ  С АРГУМЕНТАМИ ФУНКЦИИ



#include <stdio.h>fun(char *ref,char val){ *ref='j';val='*'; }main(){char alfa='e',     beta='b';fun (&alfa,beta);printf("%c%c",alfa,beta);return 0;}

Результат:
JB

#include <stdio.h>fun(arr)char arr[2][3];
{printf("\n%c%c",arr[0][0],(arr+1)[0][0]);
}
main(){
char m[2][3]={{'j'},{'b'}};
fun (m);
return 0; }

Результат:
JB


Рекурсия.  Вычисление факториала.


Рекурсия
Функции на языке С и С++ могут вызываться рекуррентно.  При каждом вызове образуются последующие автоматические переменные. Обычно подпрограмма для вычисления факториала выполняется в виде рекурсивно вызваемой функции



#include<stdio.h>float fact(int n){ return (n<=1)?1:n*fact(n-1);}main(){FILE *out;
int i;
out=fopen("test.rec","at");
for (i=1;i<=10;i++) fprintf(out,"\n F(%d)!=%.0f",i,fact(i));}

Рекурсия. Обращение строки символов.


#include<stdio.h>
#include<conio.h>
mirror(par)
char *par;
{ char chr=*par++;
if(*par)
mirror(par);
putchar(chr);}
main()
{ clrscr();
printf("Stroka\n");
mirror("Stroka");
}

Рекомендуемая электронная литература
http://aiv.spb.ru/files/index.php
  • Сайт рассылки http://c-programmer.spb.ru/ (Будет доступен с вечера понедельника 16.10.06)




     На этом я завершаю сегодняшний выпуск рассылки. Кому нужен компилятор – пишите вышлю. Есть вопросы – задавайте. 
        Желаю всем хорошего настроения, удачи, успехов в делах!
                                    Олег Павлович Маркатов.
E-mail: markatof@mail.ru

 

В избранное