Понимание функций и указателей в C - PullRequest
2 голосов
/ 24 января 2010

Это очень простой вопрос, но что означает следующий прототип функции?

int square (int y, size_t * x)

какая доза size_t * означает?Я знаю, что size_t - это тип данных (int> = 0).Но как мне прочитать * прилагается к нему?Это указатель на место в памяти для х?В общем, у меня проблемы с этим, и если бы кто-нибудь мог предоставить полезную ссылку, я был бы признателен.


Спасибо всем.Я понимаю, что такое указатель, но, думаю, мне сложно понять взаимосвязь между указателями и функциями.Когда я вижу прототип функции, определенный как int sq(int x, int y), тогда мне совершенно ясно, что происходит.Однако, когда я вижу что-то вроде int sq( int x, int* y), я не могу - на всю жизнь - понять, что на самом деле означает второй параметр.На каком-то уровне я понимаю, что это означает «передавать указатель», но я недостаточно хорошо понимаю вещи, чтобы манипулировать ими самостоятельно.

Ответы [ 11 ]

10 голосов
/ 24 января 2010

Как насчет учебника по пониманию указателей ?

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

Может возвращать значение напрямую:

float square_root( float x )
{
    if ( x >= 0 )
        return sqrt( x );
    return 0;
}

Или может быть возвращен указателем:

int square_root( float x, float* result )
{
    if ( x >= 0 )
    {
        *result = sqrt( result );
        return 1;
    }
    return 0;
}

Первый называется:

float a = square_root( 12.0 );

... а у последнего:

float b;
square_root( 12.00, &b );

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

Следовательно, с последним вы могли бы написать:

float sqresult;
if ( !square_root( myvar, &sqresult ) )
{
   // signal error
}  
else
{ 
   // value is good, continue using sqresult!
}
2 голосов
/ 25 января 2010

В ответ на ваш последний комментарий я постараюсь объяснить.

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

int sq(int x);

... тогда это означает, что функция sq требует, чтобы вы указали значение, являющееся целым числом, и вернет значение, которое также является целым числом.

Если переменная объявлена ​​с указателем типа, это означает, что значением самой этой переменной является «местоположение другой переменной». Таким образом, переменная типа int * может содержать в качестве значения «местоположение другой переменной, и эта другая переменная имеет тип int». Затем мы можем распространить это на функции:

int sqp(int * x);

Это означает, что функция sqp должна предоставить вам значение, которое само является местоположением переменной типа int. Это означает, что я мог бы назвать это так:

int p;
int q;

p = sqp(&q);

(&q просто означает «дай мне местоположение из q, а не его значение»). В пределах sqp я мог бы использовать этот указатель так:

int sqp(int * x)
{
    *x = 10;
    return 20;
}

(*x означает «воздействовать на переменную в месте, заданном x , а не на x»).

2 голосов
/ 24 января 2010
2 голосов
/ 24 января 2010

Прототип означает, что функция принимает один целочисленный аргумент и один аргумент, который является указателем на тип size_t. size_t - это тип, определенный в заголовочном файле, обычно это тип unsigned int, но причина не просто использования «unsigned int * x» состоит в том, чтобы дать авторам компилятора гибкость в использовании чего-то другого.

Указатель - это значение, которое содержит адрес памяти. Если я напишу

int x = 42;

тогда компилятор выделит 4 байта в памяти и запомнит местоположение каждый раз, когда я использую x. Если я хочу передать это местоположение явно, я могу создать указатель и присвоить ему адрес x:

int * ptr = & x;

Теперь я могу передавать ptr функциям, которые ожидают int * для аргумента, и я могу использовать ptr путем разыменования:

cout << * ptr + 1; </p>

распечатает 43. Существует ряд причин, по которым вы можете использовать указатели вместо значений. 1) вы избегаете создания структур и классов копирования при переходе к функции 2) вы можете иметь более одного дескриптора переменной 3) это единственный способ манипулировать переменными в куче 4) вы можете использовать их для передачи результатов вне функции путем записи в местоположение, указанное аргументом

2 голосов
/ 24 января 2010

* x означает, что x является указателем на ячейку памяти типа size_t.

Вы можете установить местоположение с помощью x = & y; или установите значение, на которое было указано x, с помощью: * x = 0;

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

1 голос
/ 24 января 2010

size_t *x означает, что вы передаете указатель на size_t 'instance'.

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

  1. Чтобы функция могла изменять переменную вызывающего. C использует передачу по значению, поэтому изменение параметра внутри функции не изменяет исходную переменную.
  2. По соображениям производительности. Если параметр является структурой, передача по значению означает, что вы должны скопировать структуру. Если структура достаточно велика, это может привести к снижению производительности.
0 голосов
/ 11 июля 2012

Прошло 2 года и до сих пор нет ответа? Хорошо, я попытаюсь объяснить это ...

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

int sq_A(int x, int y)

Вы знаете это - это функция с именем sq_A, которая принимает два int параметра. Легко.

int sq_B(int x, int* y)

Это функция с именем sq_B, которая принимает два параметра:

  • Параметр 1 является int

  • Параметр 2 является указателем. Это указатель, который указывает на int

Итак, когда мы вызываем sq_B(), нам нужно передать указатель в качестве второго параметр. Мы не можем просто передать любой указатель - это должен быть указатель на тип int.

Например:

int sq_B(int x, int* y) {
    /* do something with x and y and return a value */
}

int main() {
    int t = 6;
    int u = 24;
    int result;

    result = sq_B(t, &u);

    return 0;
}

В main() переменная u является int. Чтобы получить указатель на u, мы используйте оператор & - &u. Это означает «адрес u» и является указатель.

Поскольку u является int, &u является указателем на int (или int *), который является типом, указанным параметром 2 sq_B().

Есть вопросы?

0 голосов
/ 28 октября 2011

большая часть объяснения выше достаточно хорошо объяснена. Я хотел бы добавить точку зрения приложения такого рода передачи аргументов.

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

Например: глупо, но дает вам сценарий

//a function is used to get two random numbers into x,y in the main function
int main()
{    
int x,y;    
generate_rand(&x,&y);    
//now x,y contain random values generated by the function
}

void generate_rand(int *x,int *y)
{
*x=rand()%100;
*y=rand()%100;
}

2) когда передача объекта (объекта класса или структуры и т. Д.) Является дорогостоящим процессом (т. Е. Если размер слишком велик, то память и другие ограничения и т. Д.)

Например: вместо передачи структуры в функцию в качестве аргумента указатель может быть полезен, так как указатель может использоваться для доступа к структуре, но также экономит память, поскольку вы не храните структуру во временном местоположении (или в стеке). ) * +1010 *

просто пара примеров .. надеюсь, это поможет ..

0 голосов
/ 22 октября 2011

U сказал, что вы знаете, что такое int sq(int x, int y). Это означает, что мы передаем две переменные x, y в качестве параметров функции sq.Say sq вызывается из main() функции как в

main()
{
    /*some code*/
    x=sr(a,b);
    /*some other code*/
}
int sq(int x,int y)
{
    /*code*/
}

любые операции, выполняемые с функциями x, y в sq, не влияют на значения a, b в то время как в

main()
{
    /*some code*/
    x=sq(a,&b);
    /*some other code*/
}
int sq(int x,int* y)
{
    /*code*/
}

операции, выполненные на y, изменят значение b, потому что мы ссылаемся на b

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

0 голосов
/ 24 января 2010
int square( int y, size_t* x );

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

size_t - целочисленный тип без знака (обычно typedef) , возвращаемый оператором sizeof() .

* (звезда) сигнализирует тип указателя (например, int* ptr; делает ptr указателем на целое число) при использовании в объявлениях (и приведениях), или разыменование указателя при использовании в lvalue или rvalue (*ptr = 10; назначает десять памяти, на которую указывает ptr). Нам просто повезло, что этот же символ используется для умножения (например, Паскаль использует ^ для указателей).

В момент объявления функции имена параметров (x и y здесь) на самом деле не имеют значения. Вы можете определить свою функцию с разными именами параметров в файле .c. Вызывающая функция интересует только типы и количество параметров функции, а также тип возвращаемого значения.

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

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

C это красивый и простой язык:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...