Как передать указатель в функцию c
Перейти к содержимому

Как передать указатель в функцию c

  • автор:

Как передать указатель в функцию c


Next: Представление Up: Способность языка к взаимодействию Previous: Инициализация &nbsp Contents

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

Си и ФОРТРАН. Определение типа MPI_Fint предназначено в Си/С++ для целого числа размера, который соответствует INTEGER языка ФОРТРАН; часто MPI_Fint будет эквивалентен int .

Следующие функции предназначены в Си, чтобы преобразовать указатель коммуникатора языка ФОРТРАН (который является целым числом) к указателю коммуникатора языка Си, и наоборот.

MPI_Comm MPI_Comm_f2c(MPI_Fint comm)

Если comm — действительный указатель языка ФОРТРАН к коммуникатору, то MPI_Comm_f2c возвращает действительный указатель Си к тому же самому коммуникатору; если comm = MPI_COMM_NULL (значение ФОРТРАНА), то MPI_Comm_f2c возвращает нулевой указатель Си; если comm — недействительный указатель коммуникатора языка ФОРТРАН, то MPI_Comm_f2c возвращает недействительный указатель коммуникатора Си.

MPI_Fint MPI_Comm_c2f(MPI_Comm comm)

Функция MPI_Comm_c2f транслирует указатель коммуникатора языка Си в указатель языка ФОРТРАН того же самого коммуникатора; она отображает нулевой указатель в нулевой указатель и недействительный указатель в недействительный указатель.

Подобные функции предназначаются для других типов скрытых объектов.

MPI_Datatype MPI_Type_f2c(MPI_Fint datatype) MPI_Fint MPI_Type_c2f(MPI_Datatype datatype) MPI_File MPI_File_f2c(MPI_Fint file) MPI_Fint MPI_File_c2f(MPI_File file) MPl_Group MPI_Group_f2c(MPI_Fint group) MPI_Fint MPI_Group_c2f(MPI_Group group) MPI_Info MPI_Info_f2c(MPI_Fint info) MPI_Fint MPI_Info_c2f(MPI_Info info) MPI_Op MPI_Op_f2c(MPI_Fint op) MPI_Fint MPI_Op_c2f(MPI_Op op) MPI_Request MPI_Request_f2c(MPI_Fint request) MPI_Fint MPI_Request_c2f(MPI_Request request) MPI_Win MPI_Win_f2c(MPI_Fint win) MPI_Fint MPI_Win_c2f(MPI_Win win)

Пример 4.9 Пример ниже иллюстрирует, как функция MPI языка ФОРТРАН MPI_TYPE_COMMIT может быть осуществлена, упаковывая функцию MPI Си MPI_Type_commit с упаковщиком Си, чтобы сделать преобразования указателя. В этом примере принят ФОРТРАН-Си интерфейс, где функция языка ФОРТРАН набрана заглавными буквами, когда упоминается от Си, и аргументы передаются через адреса.

! ПРОЦЕДУРА ЯЗЫКА ФОРТРАН SUBROUTINE MPI_TYPE_COMMIT(DATATYPE, IERR) INTEGER DATATYPE, IERR CALL MPI_X_TYPE_COMMIT(DATATYPE, IERR) RETURN END /* Упаковщик Си */ void MPI_X_TYPE_COMMIT(MPI_Fint *f_handle, MPI_Fint *ierr)

Тот же самый подход может использоваться для всех других функций MPI . Вызов MPI_xxx_f2c (соответственно MPI_xxx_c2f ) может быть опущен, когда указатель является OUT (соответственно IN) аргументом, а не INOUT.

Объяснение: Оформление обеспечивает здесь удобное решение для распространенного случая, где используется упаковщик Си, чтобы позволить коду языка ФОРТРАН вызвать библиотеку Си, или коду Си вызвать библиотеку языка ФОРТРАН. Использование упаковщиков Си — более вероятно, чем использование упаковщиков ФОРТРАН, потому что более вероятно, что переменную типа INTEGER можно передать в Си, чем указатель Си можно передать в ФОРТРАН.

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

Си и С++. Интерфейс языка С++ обеспечивают функции, перечисленные ниже для многоязыковой способности к взаимодействию. Эстафетный используется ниже, чтобы указать любое действительное MPI скрытое имя указателя (например, Group ), кроме специально отмеченных случаев. Для случая, где происходил класс С++, соответствующий , функции класса также предназначаются для преобразования между полученными классами и MPI_ языка Си.

Следующая функция позволяет назначение от указателя MPI языка Си до указателя MPI языка С++.

MPI::& MPI::::operator=(const MPI_& data)

Конструктор ниже создает объект MPI С++ из указателя MPI Си. Это позволяет автоматическое преобразование указателя MPI языка Си к указателю MPI языка С++.

MPI::::(const MPI_& data)

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

// Прототип библиотечной функции C++ void cpp_lib_call(MPI::Comm& cpp_comm); // Экспортируемый прототип функции C extern "C" void c_interface(MPI_Comm c_comm); void c_interface(MPI_Comm c_conm) < // MPI_Comm (c_comm) автоматически преобразован к MPI::Comm cpp_lib_call(c_comm); >

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

MPI::::operator MPI_() const

Пример 4.11 Подпрограмма библиотеки Си вызывается из программы С++. Подпрограмма библиотеки Си смоделирована, чтобы принимать MPI_Comm как аргумент.

// Прототип функции Си extern "C" < void c_lib_call(MPI_Comm c_comm); >void cpp_function() < // Создает коммуникатор C++, и инициализирует его с dup // MPI::COMM_WORLD MPI::Intracomm cpp_comm(MPI::COMM.WORLD.Dup()); c_lib_call(cpp_comm); >

Объяснение: Обеспечение преобразования из Си в С++ через конструкторы и из С++ в Си через приведение позволяет компилятору делать автоматические преобразования. Вызов Си из С++ становится тривиальным, так что обеспечивается интерфейс языка Си или ФОРТРАН к библиотеке С++.[]

Совет пользователям: Обратите внимание, что операторы приведения и содействия возвращают новые указатели значения. Использование этих новых указателей как параметров INOUT затронет внутренний объект MPI , но не будет затрагивать первоначального указателя, из которого он приводился. []

Важно обратить внимание, что все объекты С++ и их соответствующие указатели Си могут взаимозаменяемо использоваться приложением. Например, приложение может кэшировать атрибут на MPI_COMM_WORLD и позже восстанавить его из MPI::COMM_WORLD .

Alex Otwagin 2002-12-10

Указатели на функции

Чаще всего к ошибкам приводит использование указателей па функцию. Хотя функция — это не переменная, она по-прежнему имеет физическое положение в памяти, которое может быть присвоено указателю. Адрес, присвоенный указателю, является входной точкой в функцию. Указатель может использоваться вместо имени функции. Он также позволяет передавать функции как обычные аргументы в другие функции.

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

Адрес функции получается при использовании имени функции без каких-либо скобок или аргументов. (Очень похоже на массивы, где адрес получается с использованием имени массива без индексов.) Рассмотрим следующую программу, предназначенную для демонстрации нюансов объявления:

#include
#include
void check(char *a, char *b, int (*cmp) (const char *, const char *));
int main(void)
char s1 [80], s2[80];
int (*p) (const char*, const char*);
p = strcmp; /* получение адреса strcmp() */
gets(s1);
gets (s2);
check(s1, s2, p);
return 0;
>

void check (char *a, char *b, int (*cmp) (const char *, const char *))
printf(«Testing for equality.\n»);
if(!(*cmp) (a, b)) printf(«Equal»);
else printf(«Not equal»);
>

Когда вызывается check(), ей передаются два указателя на символы и один указатель на функцию. В функции check() аргументы объявляются как указатели на символы и указатель на функцию. Надо обратить внимание на способ объявления указателя на функцию. Следует использовать аналогичный метод при объявлении других указателей на функцию, за исключением тех случаев, когда отличается возвращаемый тип или передаваемые параметры. Скобки вокруг *cmp необходимы для правильной интерпретации компилятором данного выражения.

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

Рассмотрим работу функции strcmp() в функции check(). Оператор

if (!(*cmp) (a, b) ) printf(«Equal»);

осуществляет вызов функции, в данном случае strcmp(), с помощью cmp, который указывает на данную функцию. Вызов происходит с аргументами a и b. Данный оператор демонстрирует общий вид использования указателя на функцию для вызова функции, на которую он указывает. Круглые скобки вокруг *cmp необходимы вследствие наличия приоритетов. На самом деле можно напрямую использовать cmp, как показано ниже:

if (!cmp(a, b)) printf(«Equal»);

Данная версия также вызывает функцию, на которую указывает cmp, но она использует нормальный синтаксис. Использование ( cmp) помогает всем, читающим программу, понять, что указатель на функцию используется для вызова функции вместо вызова функции cmp. Возможно вызвать напрямую check(), используя strcmp, как показано ниже:

check(s1, s2, strcmp);

Данный оператор устраняет необходимость наличия дополнительной переменной-указателя.

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

#include
#include
#include
#include
void check(char *a, char *b, int (*cmp) (const char *, const char *));
int numcmp (const char *a, const char *b) ;
int main(void)
char s1[80], s2 [80];
gets (s1);
gets (s2);
if(isalpha(*s1))
check (s1, s2, strcmp);
else
check(s1, s2, numcmp);
return 0;
>

void check(char *a, char *b, int (*cmp) (const char *,const char *))
printf(«Testing for equality.\n»);
if(!(*cmp) (a, b)) printf («Equal»);
else printf(«Hot equal»);
>

int numcmp (const char *a, const char *b)
If(atoi(a)==atoi(b)) return 0;
else return 1;
>

Как передать указатель в функцию c

Передача через указатель

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

Если передавать параметры через указатель (так называемый С-стиль), код функции выглядит так:

mul5(&var); // Здесь символ & обозначает операцию взятия адреса переменной

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

Передача через ссылку

Если передавать параметры через ссылку , код функции выглядит так:

А вызов выглядит так:

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

Однако, следует помнить , что такая передача по ссылке возможна только для единичных типов C/C++ . И не работает для передачи массивов!

Поэтому, к примеру, если функция принимает:

  • одномерный массив block из элементов char , элементы которого надо изменить внутри функции (обозначим это как сложный/составной тип)
  • целочислительную переменную shift , которую тоже надо изменить внутри функции (это простой базовый тип)

то реализация функции будет выглядеть так:

void clear(unsigned char *block, int &shift)

А вызов функции будет выглядеть так:

unsigned char* anyBlock=»Long string»;

clear(anyBlock, anyShift); // Вызов функции

То есть, в вызове нет никаких спецсимволов указателей/адресов ни для первого ни для второго параметра. Для первого параметра нет спецсимвола взятия адреса (хоть и идет работа с указателем) из-за того, что имя массива имеет тип указателя. Для второго параметра нет спецсимвола взятия адреса из-за того, что передача идет по ссылке.

При таком вызове будут изменяться как ячейки массива anyBlock , так и переменная anyShift .

  • Стандарт языка программирования Си
  • Передача параметра в функцию по указателю в C стиле
  • Передача параметров в функцию по указателю (C стиль) и по ссылке (C++ стиль)
  • Передача структуры в функцию и изменение значений элементов структуры
  • В чем разница объявления строки как массива и как указателя
  • Использование очень больших чисел
  • getch() в Linux
  • Аргументы функции main()
  • Как побайтно считать файл
  • Реализация циклического сдвига ROR и ROL
  • Динамическая загрузка библиотек в Linux
  • Функция fmemopen() — открытие набора байт как файла в памяти с получением файлового дескриптора
  • Подмена дефайнов (#define)
  • Успешной отладки, шутка
  • Как описывать функции с аргументами по-умолчанию в C/C++
  • Форматированный вывод через функцию printf
  • Создание и удаления двухмерного и трехмерного динамического массива
  • Как передать в функцию двумерный массив, размер которого известен
  • Как передать в функцию динамический двумерный массив
  • Как правильно читать объявления в Си
  • Вычисление pbkdf2 на языке C
  • Определение разрядности платформы 32 или 64 бит
  • Функции getuid() и geteuid()
  • Указатели и символьные строки в языке C
  • Практическое применение LD_PRELOAD или замещение функций в Linux
  • Проблемы C-подобных языков. Где находиться типу: справа или слева? (Теория)
  • Откуда в языке Си появился синтаксис указателей, и для чего он предназначался изначально
  • Как в языке Си вызвать функцию, для которой известен адрес вызова в виде числа
  • Вызов функции по известному адресу в языке Си — абстрактный тип данных указателя на функцию
  • Структуры в языке Си. Определения структур в сравнении с языком C++
  • Структуры в языке Си. Указатели на структуры
  • Структуры в языке Си. Массивы структур
  • Операция запятая «,» в языке Си и Си++
  • Самый быстрый и оптимальный способ копирования строк в Cи и C++
  • Стоит запомнить: цикл for в языке Си/Си++ — это цикл с предусловием
  • Как происходит компиляция C/C++ кода. Единица трансляции

Передача указателей в функцию C++

Вопрос по C++. При передаче обычной переменной в функцию создается, как я понимаю, её копия. А что происходит, когда мы передаем указатель? Создается ли копия указателя или нет?

Отслеживать
44.8k 3 3 золотых знака 38 38 серебряных знаков 89 89 бронзовых знаков
задан 24 дек 2016 в 23:45
113 1 1 золотой знак 1 1 серебряный знак 5 5 бронзовых знаков

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Если у вас объявлена функция с параметром, как, например,

void f( T t ); 

где T — это некоторый тип, и эта функция вызывается с некоторым выражением, переданным ей в качестве аргумента, как

f( exp ); 

то инициализацию параметра можно представить следующим образом

void f( /* T t */ ) < T t = exp; //. 

то есть параметр - это локальная переменная функции, которая инициализируется тем выражением, которое передано функции в качестве аргумента. Следовательно изменения параметра никак не сказываются на исходном аргументе, ели только тип T не является ссылочным типом.

Сравните две функции

void f( int *p ) < p = new int( 10 ); >void g( int * &p )
int main()

В этом примере при вызове функции f имеет место утечка памяти, так как память, распределенная в функции, не освобождается. Параметр функции - локальная переменная p - при выходе из функции удаляется, и тем самым адрес выделенной динамически памяти будет утерян.

У функции g параметр имеет ссылочный тип, то есть эта ссылка на переданный функции аргумент. Поэтому функция имеет дело с исходным аргументом и меняет его в своем теле, присваивая ему адрес выделенной памяти.

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

void h( int **p )

Вызов функции будет выглядеть как

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *