Смотреть что такое "Void" в других словарях.

24.06.2019

Для чего нужны функции в C?

Функции в Си применяются для выполнения определённых действий в рамках общей программы. Программист сам решает какие именно действия вывести в функции. Особенно удобно применять функции для многократно повторяющихся действий.

Простой пример функции в Cи

Пример функции в Cи:

#include #include int main(void) { puts("Functions in C"); return EXIT_SUCCESS; }

Это очень простая программа на Си. Она просто выводит строку «Functions in C». В программе имеется единственная функция под названием main. Рассмотрим эту функцию подробно. В заголовке функции, т.е. в строке

int – это тип возвращаемого функцией значения;

main - это имя функции;

(void) - это перечень аргументов функции. Слово void указывает, что у данной функции нет аргументов;

return – это оператор, который завершает выполнение функции и возвращает результат работы функции в точку вызова этой функции;

EXIT_SUCCESS - это значение, равное нулю. Оно определено в файле stdlib.h;

часть функции после заголовка, заключенная в фигурные скобки

{
puts("Functions in C");
return EXIT_SUCCESS;
}

называют телом функции.

Итак, когда мы работаем с функцией надо указать имя функции, у нас это main, тип возвращаемого функцией значения, у нас это int, дать перечень аргументов в круглых скобках после имени функции, у нас нет аргументов, поэтому пишем void, в теле функции выполнить какие-то действия (ради них и создавалась функция) и вернуть результат работы функции оператором return. Вот основное, что нужно знать про функции в C.

Как из одной функции в Cи вызвать другую функцию?

Рассмотрим пример вызова функций в Си:

/* Author: @author Subbotin B.P..h> #include int main(void) { puts("Functions in C"); int d = 1; int e = 2; int f = sum(d, e); printf("1 + 2 = %d", f); return EXIT_SUCCESS; }

Запускаем на выполнение и получаем:

В этом примере создана функция sum, которая складывает два целых числа и возвращает результат. Разберём подробно устройство этой функции.

Заголовок функции sum:

int sum(int a, int b)

здесь int - это тип возвращаемого функцией значения;

sum - это имя функции;

(int a, int b) - в круглых скобках после имени функции дан перечень её аргументов: первый аргумент int a, второй аргумент int b. Имена аргументов являются формальными, т.е. при вызове функции мы не обязаны отправлять в эту функцию в качестве аргументов значения перемнных с именами a и b. В функции main мы вызываем функцию sum так: sum(d, e);. Но важно, чтоб переданные в функцию аргументы совпадали по типу с объявленными в функции.

В теле функции sum, т.е. внутри фигурных скобок после заголовка функции, мы создаем локальную переменную int c, присваиваем ей значение суммы a плюс b и возвращаем её в качестве результата работы функции опрератором return.

Теперь посмотрим как функция sum вызывается из функции main.

Вот функция main:

Int main(void) { puts("Functions in C"); int d = 1; int e = 2; int f = sum(d, e); printf("1 + 2 = %d", f); return EXIT_SUCCESS; }

Сначала мы создаём две переменных типа int

Int d = 1; int e = 2;

их мы передадим в функцию sum в качестве значений аргументов.

int f = sum(d, e);

её значением будет результат работы функции sum, т.е. мы вызываем функцию sum, которая возвратит значение типа int, его-то мы и присваиваем переменной f. В качестве аргументов передаём d и f. Но в заголовке функции sum

int sum(int a, int b)

аргументы называются a и b, почему тогда мы передаем d и f? Потому что в заголовке функций пишут формальные аргументы, т.е. НЕ важны названия аргументов, а важны их типы. У функции sum оба аргумента имеют тип int, значит при вызове этой функции надо передать два аргумента типа int с любыми названиями.

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

Прототип функции в Си

Рассмотрим пример функциив Си:

/* Author: @author Subbotin B.P..h> #include int sum(int a, int b); int main(void) { puts("Functions in C"); int d = 1; int e = 2; int f = sum(d, e); printf("1 + 2 = %d", f); return EXIT_SUCCESS; } int sum(int a, int b) { int c = 0; c = a + b; return c; }

В этом примере функция sum определена ниже места её вызова в функции main. В таком случае надо использовать прототип функции sum. Прототип у нас объявлен выше функции main:

int sum(int a, int b);

Прототип - это заголовок функции, который завершается точкой с запятой. Прототип - это объявление функции, которая будет ниже определена. Именно так у нас и сделано: мы объявили прототип функции

int f = sum(d, e);

а ниже функции main определяем функцию sum, которая предварительно была объявлена в прототипе:

Int sum(int a, int b) { int c = 0; c = a + b; return c; }

Чем объявление функции в Си отличается от определения функции в Си?

Когда мы пишем прототип функции, например так:

int sum(int a, int b);

то мы объявляем функцию.

А когда мы реализуем функцию, т.е. записываем не только заголовок, но и тело функции, например:

Int sum(int a, int b) { int c = 0; c = a + b; return c; }

то мы определяем функцию.

Оператор return

Оператор return завершает работу функции в C и возвращает результат её работы в точку вызова. Пример:

Int sum(int a, int b) { int c = 0; c = a + b; return c; }

Эту функцию можно упростить:

Int sum(int a, int b) { return a + b; }

здесь оператор return вернёт значение суммы a + b.

Операторов return в одной функции может быть несколько. Пример:

Int sum(int a, int b) { if(a > 2) { return 0;// Первый случай; } if(b < 0) { return 0;// Второй случай; } return a + b; }

Если в примере значение аргумента a окажется больше двух, то функция вернет ноль (первый случай) и всё, что ниже комментария «// Первый случай;» выполнятся не будет. Если a будет меньше двух, но b будет меньше нуля, то функция завершит свою работу и всё, что ниже комментария «// Второй случай;» выполнятся не будет.

И только если оба предыдущих условия не выполняются, то выполнение программы дойдёт до последнего оператора return и будет возвращена сумма a + b.

Передача аргументов функции по значению

Аргументы можно передавать в функцию C по значению. Пример:

/* Author: @author Subbotin B.P..h> #include int sum(int a) { return a += 5; } int main(void) { puts("Functions in C"); int d = 10; printf("sum = %d\n", sum(d)); printf("d = %d", d); return EXIT_SUCCESS; }

В примере, в функции main, создаём переменную int d = 10. Передаём по значению эту переменную в функцию sum(d). Внутри функции sum значение переменной увеличивается на 5. Но в функции main значение d не изменится, ведь она была передана по значению. Это означает, что было передано значение переменной, а не сама переменная. Об этом говорит и результат работы программы:

т.е. после возврата из функции sum значеие d не изменилось, тогда как внутри функции sum оно менялось.

Передача указателей функции Си

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

/* Author: @author Subbotin B.P..h> #include int sum(int *a) { return *a += 5; } int main(void) { puts("Functions in C"); int d = 10; printf("sum = %d\n", sum(&d)); printf("d = %d", d); return EXIT_SUCCESS; }

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

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

в функцию sum передается не значение переменной d, равное 10-ти, а адрес этой переменной, вот так:

Теперь посмотрим на функцию sum:

Int sum(int *a) { return *a += 5; }

Аргументом её является указатель на int. Мы знаем, что указатель - это переменная, значением которой является адрес какого-то объекта. Адрес переменной d отправляем в функцию sum:

Внутри sum указатель int *a разыменовывается. Это позволяет от указателя перейти к самой переменной, на которую и указывает наш указатель. А в нашем случае это переменная d, т.е. выражение

равносильно выражению

Результат: функция sum изменяет значение переменной d:

На этот раз изменяется значение d после возврата из sum, чего не наблюдалось в предыдущм пункте, когда мы передавали аргумент по значению.

C/C++ в Eclipse

Все примеры для этой статьи я сделал в Eclipse. Как работать с C/C++ в Eclipse можно посмотреть . Если вы работаете в другой среде, то примеры и там будут работать.

Теги: void*, пустые указатели, неопределённые указатели.

Указатели типа void

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

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

#include #include int main() { void *p = NULL; int intVar = 10; char charVar = "A"; float floatVar = 24.3; float *floatPtr = NULL; p = &intVar; *((int*) p) = 20; printf("intVar = %d\n", intVar); p = &charVar; printf("charVar = %c\n", *((char*) p)); p = &floatVar; floatPtr = (float*) p; printf("floatVar = %.3f", *floatPtr); getch(); }

Переменная не может иметь типа void, этот тип определён только для указателей. Пустые указатели нашли широкое применение при вызове функций. Можно написать функцию общего назначения, которая будет работать с любым типом. Например, напишем функцию swap, которая обменивает местами содержимое двух переменных. У этой функции будет три аргумента – указатели на переменные, которые необходимо обменять местами и их размер.

#include #include #include #include void swap(void *a, void *b, size_t size) { char* tmp; //создаём временную переменную для обмена tmp = (char*) malloc(size); memcpy(tmp, a, size); memcpy(a, b, size); memcpy(b, tmp, size); free(tmp); } int main() { float a = 10.f; float b = 20.f; double c = 555; double d = 777; unsigned long e = 2ll; unsigned long f = 3ll; printf("a = %.3f, b = %.3f\n", a, b); swap(&a, &b, sizeof(float)); printf("a = %.3f, b = %.3f\n", a, b); printf("c = %.3f, d = %.3f\n", c, d); swap(&c, &d, sizeof(double)); printf("c = %.3f, d = %.3f\n", c, d); printf("e = %ld, f = %ld \n", e, f); swap(&e, &f, sizeof(unsigned long)); printf("e = %ld, f = %ld \n", e, f); getch(); }

Наша функция может выглядеть и по-другому. Обойдёмся без дорогостоящего выделения памяти и будем копировать побайтно.

Void swap(void *a, void *b, size_t size) { char tmp; size_t i; for (i = 0; i < size; i++) { tmp = *((char*) b + i); *((char*) b + i) = *((char*) a + i); *((char*) a + i) = tmp; } }

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

Int cmpInt(void* a, void* b) { return *((int*) a) - *((int*) b); } int cmpString(void *a, void* b) { return strcmp((char*) a, (char*) b); } int cmpFloat(void* a, void* b) { float fdiff = *((float*) a) - *((float*) b); if (fabs(fdiff) < 0.000001f) { return 0; } if (fdiff < 0) { return -1; } else { return 1; } }

Ru-Cyrl 18- tutorial Sypachev S.S. 1989-04-14 [email protected] Stepan Sypachev students

Всё ещё не понятно? – пиши вопросы на ящик

Среди современных языков программирования ключевое слово void впервые появилось в Си++ для поддержки концепции обобщенных указателей . Тем не менее, благодаря скорому заимствованию у Си++, первым нормативным документом, содержащим это ключевое слово, стал стандарт языка Си, опубликованный ANSI в 1989 г. В рамках языка Си++ void был стандартизован в 1998 г.

Впоследствии ключевое слово void и связанные с ним языковые конструкции были унаследованы языками Java и C#, D.

Синтаксис

Синтаксически, void является одним из спецификаторов типа, входящих в более общую группу спецификаторов объявления , но в некоторых языках программирования реализован в виде оператора. Например, в языке JavaScript void является оператором и всегда возвращает undefined:

void expression === undefined;

Семантика

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

  • В качестве имени типа значения, возвращаемого функцией: указывает на то, что функция не возвращает значения, а вызов такой функции является void-выражением . Тело такой функции не должно содержать операторов return с выражениями. Например:

    Язык Си до введения void

    До публикации первого стандарта Си в 1989 г., которая ввела в язык ключевое слово void общепринятой практикой было объявлять функции, не возвращающие значений без использования спецификаторов типов. Хотя семантически такое объявление было эквивалентно объявлению функции, возвращающей значение типа int , намеренно опущенные спецификаторы типа подчеркивали, что функция не возвращает никакого определенного значения. Например:

    f(long l) { /* ... */ }

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

    int main() { /* ... */ }

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

    Первый стандартный диалект Си (C89), хотя уже позволял записи с ключевым словом void , все же допускал такое использование неявного int в целях поддержки совместимости с существующим кодом. Современный диалект Си (C99) не допускает отсутствия спецификаторов типов в именах типов и объявлениях.

    Примеры

    Показаны примеры объявления функции, возвращающей void.

    C++

    Java

    C#

    C

    void message(void)

    Objective-C

    -(void) message;

    D

    ActionScript

    function message() : void

    Напишите отзыв о статье "Void"

    Примечания

    Отрывок, характеризующий Void

    – Я не знаю, как отвечать на ваш вопрос, – сказал он, покраснев, сам не зная от чего. – Я решительно не знаю, что это за девушка; я никак не могу анализировать ее. Она обворожительна. А отчего, я не знаю: вот всё, что можно про нее сказать. – Княжна Марья вздохнула и выражение ее лица сказало: «Да, я этого ожидала и боялась».
    – Умна она? – спросила княжна Марья. Пьер задумался.
    – Я думаю нет, – сказал он, – а впрочем да. Она не удостоивает быть умной… Да нет, она обворожительна, и больше ничего. – Княжна Марья опять неодобрительно покачала головой.
    – Ах, я так желаю любить ее! Вы ей это скажите, ежели увидите ее прежде меня.
    – Я слышал, что они на днях будут, – сказал Пьер.
    Княжна Марья сообщила Пьеру свой план о том, как она, только что приедут Ростовы, сблизится с будущей невесткой и постарается приучить к ней старого князя.

    Женитьба на богатой невесте в Петербурге не удалась Борису и он с этой же целью приехал в Москву. В Москве Борис находился в нерешительности между двумя самыми богатыми невестами – Жюли и княжной Марьей. Хотя княжна Марья, несмотря на свою некрасивость, и казалась ему привлекательнее Жюли, ему почему то неловко было ухаживать за Болконской. В последнее свое свиданье с ней, в именины старого князя, на все его попытки заговорить с ней о чувствах, она отвечала ему невпопад и очевидно не слушала его.
    Жюли, напротив, хотя и особенным, одной ей свойственным способом, но охотно принимала его ухаживанье.
    Жюли было 27 лет. После смерти своих братьев, она стала очень богата. Она была теперь совершенно некрасива; но думала, что она не только так же хороша, но еще гораздо больше привлекательна, чем была прежде. В этом заблуждении поддерживало ее то, что во первых она стала очень богатой невестой, а во вторых то, что чем старее она становилась, тем она была безопаснее для мужчин, тем свободнее было мужчинам обращаться с нею и, не принимая на себя никаких обязательств, пользоваться ее ужинами, вечерами и оживленным обществом, собиравшимся у нее. Мужчина, который десять лет назад побоялся бы ездить каждый день в дом, где была 17 ти летняя барышня, чтобы не компрометировать ее и не связать себя, теперь ездил к ней смело каждый день и обращался с ней не как с барышней невестой, а как с знакомой, не имеющей пола.
    Дом Карагиных был в эту зиму в Москве самым приятным и гостеприимным домом. Кроме званых вечеров и обедов, каждый день у Карагиных собиралось большое общество, в особенности мужчин, ужинающих в 12 м часу ночи и засиживающихся до 3 го часу. Не было бала, гулянья, театра, который бы пропускала Жюли. Туалеты ее были всегда самые модные. Но, несмотря на это, Жюли казалась разочарована во всем, говорила всякому, что она не верит ни в дружбу, ни в любовь, ни в какие радости жизни, и ожидает успокоения только там. Она усвоила себе тон девушки, понесшей великое разочарованье, девушки, как будто потерявшей любимого человека или жестоко обманутой им. Хотя ничего подобного с ней не случилось, на нее смотрели, как на такую, и сама она даже верила, что она много пострадала в жизни. Эта меланхолия, не мешавшая ей веселиться, не мешала бывавшим у нее молодым людям приятно проводить время. Каждый гость, приезжая к ним, отдавал свой долг меланхолическому настроению хозяйки и потом занимался и светскими разговорами, и танцами, и умственными играми, и турнирами буриме, которые были в моде у Карагиных. Только некоторые молодые люди, в числе которых был и Борис, более углублялись в меланхолическое настроение Жюли, и с этими молодыми людьми она имела более продолжительные и уединенные разговоры о тщете всего мирского, и им открывала свои альбомы, исписанные грустными изображениями, изречениями и стихами.
    Жюли была особенно ласкова к Борису: жалела о его раннем разочаровании в жизни, предлагала ему те утешения дружбы, которые она могла предложить, сама так много пострадав в жизни, и открыла ему свой альбом. Борис нарисовал ей в альбом два дерева и написал: Arbres rustiques, vos sombres rameaux secouent sur moi les tenebres et la melancolie. [Сельские деревья, ваши темные сучья стряхивают на меня мрак и меланхолию.]
    В другом месте он нарисовал гробницу и написал:
    «La mort est secourable et la mort est tranquille
    «Ah! contre les douleurs il n"y a pas d"autre asile».
    [Смерть спасительна и смерть спокойна;
    О! против страданий нет другого убежища.]
    Жюли сказала, что это прелестно.
    – II y a quelque chose de si ravissant dans le sourire de la melancolie, [Есть что то бесконечно обворожительное в улыбке меланхолии,] – сказала она Борису слово в слово выписанное это место из книги.

В 1989г. В рамках языка Си++ void был стандартизован в 1998г.

Впоследствии ключевое слово void и связанные с ним языковые конструкции были унаследованы языками Java и C#, D.

Синтаксис

Синтаксически, void является одним из спецификаторов типа, входящих в более общую группу спецификаторов объявления, но в некоторых языках программирования реализован в виде оператора. Например, в языке JavaScript void является оператором и всегда возвращает undefined:

Void expression === undefined ;

Семантика

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

  • В качестве имени типа значения, возвращаемого функцией: указывает на то, что функция не возвращает значения, а вызов такой функции является void-выражением. Тело такой функции не должно содержать операторов return с выражениями. Например:

    Void f() ;

  • В составе декларатора функции: указывает на то, что функция имеет прототип и не имеет параметров. Например:

    Int f(void ) ;

  • В качестве имени целевого типа операции приведения: такое void-приведение означает отказ от значения приводимого выражения. Например:

    #define promote_ptr() ((void) (ptr++))

  • В составе имени типа void-указателя: такой указатель способен представлять значения любых указателей на объектные и неполные типы, т.е. адреса любых объектов . Таким образом, void -указатель является обобщенным объектным указателем. void -указатели не способны представлять значения указателей на функции. За исключением случая приведения константного null-указателя к указателю на функцию в Си, явных и неявных преобразований между void -указателями и указателями на функции нет.

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

Язык Си до введения void

До публикации первого стандарта Си в 1989г., которая ввела в язык ключевое слово void общепринятой практикой было объявлять функции, не возвращающие значений без использования спецификаторов типов. Хотя семантически такое объявление было эквивалентно объявлению функции, возвращающей значение типа int , намеренно опущенные спецификаторы типа подчеркивали, что функция не возвращает никакого определенного значения. Например:

F(long l) { /* ... */ }

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

Int main() { /* ... */ }

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

Первый стандартный диалект Си (C89), хотя уже позволял записи с ключевым словом void , все же допускал такое использование неявного int в целях поддержки совместимости с существующим кодом. Современный диалект Си (C99) не допускает отсутствия спецификаторов типов в именах типов и объявлениях.

Примеры

Показаны примеры объявления функции, возвращающей void.

C++

Void message()

Java

Void message()

C#

Void message()

C

Void message(void )

Objective-C

- (void ) message;

D

Void message()

ActionScript

Function message () : void

Примечания


Wikimedia Foundation . 2010 .

Похожие статьи