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

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

Функция swap(), которая должна менять значения параметров местами, не будет фактически это делать.

Void swap(int a, int b)

{

int tmp=a;

a=b;

b=tmp;

}

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

Функция swap1() будет теперь выглядеть так:

void swap1(int *a, int *b)

{

int tmp=*a;

*a=*b;

*b=tmp;

}

Иллюстрацию использования этих двух способов передачи параметров дает следующая программа:

#include <stdio.h>

Void swap(int a, int b);

void swap1(int *a, int *b);

Void main(void)

{

int x=5, y=10;

printf(“Сначала x = %d y = %d\n”, x, y);

Swap(x, y);

printf(“После вызова swap x = %d y = %d\n”, x, y);

printf(“Ничего не изменилось”);

swap1(&x, &y); /* теперь передаем адреса переменных */

printf(“После вызова swap1 x = %d y = %d\n”, x, y);

printf(“Значения поменялись”);

Return 0;

}

// функции описаны выше

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

Сначала x=5, y=10

После вызова swap x=5, y=10

Ничего не изменилось

После вызова swap1 x=10, y=5

Особенности вызова: swap(5,10); /* можно */ swap1(&5,&10); /* нельзя */

Если в качестве аргумента функции используется массив, есть лишь один способ – передача параметров по ссылке. В качестве аргумента функции надо указать адрес начала массива. Это можно сделать следующими способами:

function(int ar[10]);

function(int ar[]);

function(int *ar);

Пример функции для работы с массивом:

#include <stdio.h>

void sort(int ar[], int n);

Void main(void)

{

int mass[10]={1, 3, -5, 7, 9, 0, 22, 4, 6, 8};

int size=10,i;

printf(“Before sorting:”);

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

printf(“%d”,mass[i]);

printf(“\n”);

Sort(mass, size);

printf(“After sorting:”);

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

printf(“%d”,mass[i]);

printf(“\n”);

}

void sort(int ar[], int n)

/* можно заголовок заменить на void sort(int ar[10], int n) или void sort(int *ar, int n) */

{

Int i,j,tmp;

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

{

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

{

if (ar[i]>ar[j])

{

tmp=ar[i];

ar[i]=ar[j];

ar[j]=tmp;

}

}

}

}

 

Пример программы умножения двух матриц размера

#include <stdio.h>

void multiply(int U[3][3], int V[3][3], int W[3][3]);

Void main(void)

{

int A[3][3] = {0, 1, 2,

3, 4, 5,

6, 7, 8};

int B[3][3] = {0, 1, 2,

3, 4, 5,

6, 7, 8};

int i, j, С[3][3];

Multiply(A, B, C);

printf(“Matrix C:\n”);

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

printf(“%d %d %d\n”,C[i][0], C[i][1], C[i][2]);

}

void multiply(int U[3][3], int V[3][3], int W[3][3])

{

Int i, j, k;

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

{

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

{

W[i][j]=0;

For(k=0; k<3; k++)

W[i][j]+=U[i][k]*V[k][j];

}

}

}

Массивы и указатели

Массив – одна из наиболее простых и известных структур данных. Под массивом в языке С понимают набор данных одного и того же типа, собранных под одним именем. Каждый элемент массива определяется именем массива и порядковым номером элемента, который называется индексом. Индекс в языке С всегда целое число.

Объявление массива в программе

Основная форма объявления массива размерности N такова:

тип <имя массива>[размер1][размер2]…[размерN];

Размер массива в языке С можно задавать константой или константным выражением. Нельзя задавать массив переменного размера. Для этого существует отдельный механизм, называемый динамической памятью. В языке С индекс всегда начинается с нуля. Когда говорим о первом элементе массива, то имеем в виду элемент с индексом 0. Для одномерного массива легко подсчитать, сколько байт в памяти будет занимать массив:

Количество байт=<размер базового типа>*<количество элементов>

Можно определить массив любого определенного ранее типа, например

unsigned arr[40], long double b[10][10], char ch[80];

Массивы символов. Строки.

Массивы типа char – символьные массивы – занимают в языке С особое место. Во многих языках есть специальный тип данных – строка символов (string).В С отдельного типа строки символов нет, а реализована работа со строками путем использования одномерных массивов типа char.В С, символьная строка – это одномерный массив типа char, заканчивающийся нулевым байтом (каждый бит байта равен 0). Для нулевого байта определена специальная символьная константа ‘\0’. Это следует учитывать при описании соответствующего массива символов. Так, если строка должна содержать N символов, то в описании массива следует указать N+1 элемент.

Например, описание

char str[11];

предполагает, что строка содержит 10 символов, а последний байт зарезервирован под нулевой байт.

Язык С допускает строковые константы. Строковая константа – это список литер, заключенных в двойные кавычки. Например,

“Borland C++”

В памяти это будет выглядеть так

B o r l a n d   C + + \0

 

Есть два простых способа ввода строки с клавиатуры:

Функция scanf() со спецификатором ввода %s обеспечивает ввод символов до первого пробела.

Функция gets() (из файла stdio.h) позволяет вводить строки, содержащие пробелы. Ввод оканчивается нажатием клавиши Enter. Обе функции автоматически ставят в конец строки нулевой байт. В качестве параметра в этих функциях используется просто имя массива.

Вывод строк производится функциями printf() или puts(). Обе функции выводят содержимое массива до первого нулевого байта. Функция puts() добавляет в конце выводимой строки символ новой строки. В функции printf() переход на новую строку надо предусматривать в строке формата самим.

Пример

#include <stdio.h>

/* ввод строки с клавиатуры */

Void main(void)

{

char str[80]; /* место под строку */

printf(“Bведите строку длиной менее 80 символов: “);

gets(str); /* чтение строки с клавиатуры, пока не нажата клавиша Enter */

printf(“Вы ввели строку %s \n”,str);

printf(“Bведите еще одну строку длиной менее 80 символов: “);

scanf(“%s”,&str); /* чтение строки с клавиатуры, пока не встретится пробел */

printf(“Вы ввели строку ”);

Puts(str);

}

Функции работы со строками

Для работы со строками существует специальная библиотека, описание которой находится в файле string.h.

Наиболее часто используются функции