source

포인터는 C에서 참조에 의한 호출 방식으로 간주됩니까?

goodcode 2022. 8. 21. 14:08
반응형

포인터는 C에서 참조에 의한 호출 방식으로 간주됩니까?

제가 다니는 대학의 C프로그래밍 수업에서 교수와 그녀가 쓴 후속 저서는 C의 포인터를 언급할 때 call 또는 pass by reference라는 용어를 사용합니다.

교수님이 '참조별 호출 함수'로 간주하는 예를 다음에 제시하겠습니다.

int sum(int *a, int *b);

교수님이 '값별 호출 함수'라고 생각하는 것의 예:

int sum(int a, int b);

C는 콜을 지원하지 않는 으로 알고 있습니다.가 알기로는 포인터는 가치로 통한다.

기본적으로 포인터가 C의 참조 패스 방식이라고 하는 것은 잘못된 것입니까?C에서는 참조로 통과할 수 없지만 포인터를 사용할 수 있다고 하는 것이 더 정확할까요?


업데이트 11/11/15

제 질문의 발상으로부터, 저는 용어에 대한 논쟁이 일어났다고 생각합니다만, 사실 저는 두 가지 특정한 차이점을 발견하게 되었습니다.

  • pass-by-reference(오늘날 주로 사용되는 용어):C++와 같은 언어에서 사용되는 특정 용어
  • Pass-by-reference(교수님이 포인터를 설명하는 패러다임으로 사용하는 용어):C++와 같은 언어가 개발되기 전에 사용된 일반적인 용어이며, 따라서 용어를 다시 쓰기 전에 사용되었습니다.

@Haris의 최신 답변을 읽고 이것이 왜 그렇게 흑백이 아닌지 이해할 수 있다.

C에서는 참조로 통과할 수 없지만 포인터를 대체로 사용할 수 있습니다.

네, 맞아요.


좀 더 자세히 설명하자면.c 함수에 대한 인수로 전달되는 것은 모두 값에 의해서만 전달됩니다.변수 값인지 변수 주소인지 여부입니다.

차이를 만드는 것은 당신이 보내는 것입니다.

값을 하나씩 전달할 때 변수 값을 함수에 전달합니다.참조를 통해 변수의 별칭을 함수에 전달합니다.C는 포인터를 함수에 전달할 수 있지만 이는 여전히 pass-by-value입니다.포인터의 값인 주소를 함수에 복사하는 것입니다.


  • 변수 값을 보내는 경우 함수에 의해 값만 수신되고 원래 값에는 영향을 주지 않습니다.

  • 변수의 주소를 송신하는 경우는, 값(이 경우는 주소)만이 송신됩니다만, 변수의 주소가 있기 때문에, 원래의 값을 변경하는 데 사용할 수 있습니다.


예를 들어 값별 콜과 참조별 콜의 실제 차이를 이해하기 위해 몇 가지 C++ 코드를 볼 수 있습니다.이 웹사이트에서 가져온 것입니다.

// Program to sort two numbers using call by reference. 
// Smallest number is output first.

#include <iostream>
using namespace std;

// Function prototype for call by reference
void swap(float &x, float &y);

int main()
{
   float a, b;

   cout << "Enter 2 numbers: " << endl;
   cin >> a >> b;
   if(a>b) 
     swap(a,b); // This looks just like a call-by-value, but in fact
                // it's a call by reference (because of the "&" in the
                // function prototype

   // Variable a contains value of smallest number
   cout << "Sorted numbers: ";
   cout << a << " " << b << endl;
   return 0;
}

// A function definition for call by reference
// The variables x and y will have their values changed.

void swap(float &x, float &y)
// Swaps x and y data of calling function
{
   float temp;

   temp = x;
   x = y;
   y = temp;
}

이 C++ 예에서는 참조 변수(C에는 없는 변수)가 사용되고 있습니다.이 웹사이트를 인용하자면,

"참조란 기존 변수의 별칭 또는 대체 이름입니다..."

그리고.

"참조의 주요 용도는 패스바이 레퍼런스를 지원하기 위한 함수 형식 매개 변수 역할을 하는 것입니다.."

이것은 포인터를 함수 파라미터로 사용하는 것과는 다릅니다.그 이유는 다음과 같습니다.

포인터 변수(또는 짧게는 포인터)는 기본적으로 데이터를 저장할 수 있는 다른 변수와 동일합니다.값(int, double, char 등)을 저장하는 일반 변수와는 달리 포인터는 메모리 주소를 저장합니다."

즉, 기본적으로 주소를 보내고 포인터를 통해 수신할 때는 값만 보내지만 참조 변수를 보내고 받을 때는 별칭 또는 참조를 보냅니다.


**UPDATE : 11 November, 2015**

C채팅룸에서는 오랜 토론이 있었고, 이 질문에 대한 코멘트와 답변을 읽은 후, 저는 이 질문을 바라보는 다른 방법, 즉 다른 관점이 있을 수 있다는 것을 깨달았습니다.

간단한 C 코드를 몇 가지 살펴보겠습니다.

int i;
int *p = &i;
*p = 123;

시나리오에서는 p의 이 i에 대한 참조라는 용어를 사용할 수 있습니다.이 경우 같은 포인터를 송신합니다(int* p 「」라고 하는 「이러다」라고 수 i의 참조가 함수에 송신되기 때문에, 이것을 패스 바이 레퍼런스라고 부릅니다.

즉, 용어 및 시나리오의 관점에서의 문제입니다.

나는 그 주장에 완전히 반대하지는 않을 것이다.하지만 책과 규칙을 완전히 따르는 사람에게는 이것은 잘못된 것이다.


메모: 이 채팅에서 영감을 받아 업데이트하십시오.

"참조 통과"는 개념입니다.예, 포인터 값을 함수에 전달하지만 이 경우 포인터 값을 사용하여 변수를 참조합니다.

다른 사람들은 포인터의 통과를 참조로 지칭하는 것은 잘못되었다고 설명하면서 동전으로 나사를 조일 수 있지만 그것이 동전을 드라이버라고 부르는 것을 의미하지는 않는다고 말했다.나는 그것이 훌륭한 비유라고 말하고 싶지만, 그들은 잘못된 결론에 도달한다.사실 동전이 스크루드라이버라고는 할 수 없지만 포인터는 c++ 참조와 동일하지 않지만 참조에 의해 IS를 통과시키기 위해 사용하고 있는 것은 마찬가지입니다.

C에는 "참조 통과"가 있습니까?

사실 그렇지 않아요.

엄밀히 말하면 C는 항상 패스 바이 값을 사용합니다. 포인터를 받아들이는 함수를 정의하고 호출 연산자를 사용하여 패스 바이 레퍼런스를 시뮬레이트할 있습니다.또, 컴파일러는, 배열을 함수에 건네줄 때에, 기본적으로 시뮬레이션을 실시합니다(대신, 포인터를 건네줌으로써, 질문 6.4등을 참조).

또 다른 방법은 파라미터에 타입이 있는 경우, 예를 들어 정수는 참조에 의해 전달되고 정수에 대한 포인터는 값에 의해 전달되는 것입니다.

기본적으로 C는 참조에 의한 정식 또는 c++ 참조 파라미터와 실질적으로 동등한 것은 없습니다.

포인터가 값에 의해 전달된다는 것을 증명하기 위해 포인터를 사용한 번호 교환의 예를 살펴보겠습니다.

int main(void)
{
    int num1 = 5;
    int num2 = 10;

    int *pnum1 = &num1;
    int *pnum2 = &num2;
    int ptemp;

    printf("Before swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
    temp = pnum1;
    pnum1 = pnum2;
    pnum2 = ptemp;

    printf("After swap, *Pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}

번호를 교환하는 대신 포인터가 교환됩니다.이제 동일한 함수를 만듭니다.

void swap(int *pnum1, int *pnum2)
{
     int *ptemp = pnum1;
     pnum1 = pnum2;
     pnum2 = temp;
}

int main(void)
{
    int num1 = 5;
    int num2 = 10;

    int *pnum1 = &num1;
    int *pnum2 = &num2;

    printf("Before swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
    swap(pnum1, pnum2);

    printf("After swap, *pnum1 = %d and *pnum2 = %d\n", *pnum1, *pnum2);
}

쾅! 맞바꾸면 안 돼!


일부 튜토리얼에서는 포인터 참조를 콜 바이 레퍼런스로 언급하고 있는데, 이는 오해를 불러일으킬 수 있습니다.참조에 의한 전달과 값에 의한 전달의 차이에 대해서는, 회답을 참조해 주세요.

여기서 참조는 오버로드된 용어입니다.일반적으로 참조는 단순히 무언가를 참조하는 방법입니다.포인터는 가리키는 오브젝트를 가리키며 포인터를 오브젝트에 (값으로) 건네주는 것이 C에서 참조로 건네주는 표준 방법입니다.

C++는 참조를 표현하는 더 나은 방법으로 참조 유형을 도입하고 기술 영어에 모호성을 도입했습니다. 왜냐하면 이제 참조 유형을 사용하여 참조 대상을 참조로 전달할 수 있기 때문입니다.

C++ 컨텍스트에서는 IMO는 사용되지 않습니다.다만, 전자의 용도는 애매함이 없는 다른 상황(예를 들면 순수 C)에서는 일반적인 것이라고 생각한다.

C99 표준(강조 광산)에서:

6.2.5 타입

20 다음과 같이 개체와 함수 유형에서 파생 유형을 얼마든지 구성할 수 있습니다.

...

: 포인터 유형은 참조 유형이라고 하는 함수 유형 또는 개체 유형에서 파생될 수 있습니다.포인터 유형은 참조된 유형의 엔티티에 대한 참조를 제공하는 값을 가진 개체를 나타냅니다.참조된 타입 T에서 파생된 포인터 타입은 "T로의 포인터"라고 불리기도 합니다.참조된 형식에서 포인터 유형을 구성하는 것을 "pointer type derivation"이라고 합니다.포인터 유형은 완전한 개체 유형입니다.

이상에 근거해, 당신의 교수님이 말씀하신 것은 일리가 있고 옳습니다.포인터는 값에 따라 함수에 전달됩니다.포인터가 유효한 엔티티를 가리킬 경우 해당 값은 엔티티에 대한 참조를 제공합니다.

C는 값, 마침표로 인수를 전달합니다.그러나 포인터는 참조에 의해 효과적으로 인수를 전달하기 위해 사용할 수 있는 메커니즘입니다.동전이 스크류 드라이버로서 유효하게 사용되는 것과 같이, 동전으로 동작하는 나사 슬릿도 있습니다.그들은 여전히 동전을 실제 드라이버로 바꾸지 않는다.

C++로 하다C++ 참조는 포인터보다 훨씬 제한적이며 (암묵적인 변환이 더 많음에도 불구하고) 데이터 구조의 일부가 될 수 없으며, 그 사용은 일반적인 참조별 호출 코드와 매우 비슷해 보이지만, 그 의미론은 참조별 호출 파라미터의 요구에 매우 부합하도록 요구되지만, 여전히 그것보다 더 구체적이다.Fortran 매개 변수 또는 Pascal과 같은 순수한 참조별 구현의 경우var이 파라미터는 함수 콜콘텍스트를 벗어나 완전히 참조를 사용할 수 있습니다.

교수님 말씀이 맞아요.값에 따라 복사됩니다.참조에 따르면 복사되지 않으며, 참조에는 위치가 나와 있습니다.

값에 따라 int를 함수에 전달하면 해당 함수는 복사되지만 복사본에 대한 변경은 원본에 영향을 주지 않습니다.

참조에 의해, 포인터와 같은 int를 전달해, 카피되지 않고, 원본을 변경합니다.

참조에 따르면 어레이는 항상 레퍼런스이며 어레이에 10억 개의 아이템이 있을 수 있습니다.원본을 수정하고 있다고만 하는 것이 더 빠릅니다.

pass-by-reference를 지원하는 언어에서는 호출된 함수가 반환될 때까지 호출자에게 알려진 변수를 식별하기 위해 사용할 수 있는 함수를 제공할 수 있는 수단이 존재하지만, 그 이후에는 존재하지 않는 장소에만 저장할 수 있다.그 결과, 호출자는 어떤 함수에 대한 참조를 전달한 결과로 변수에 대해 수행되는 모든 것이 함수가 반환될 때까지 수행된다는 것을 알 수 있다.

C 프로그램과 C# 프로그램을 비교합니다.

// C               // C#
int x=0;           int x=0;
foo(&x);           foo(ref x);
x++;               x++;
bar();             bar();
x++;               x++;
boz(x);            boz(x);

foo()가 무제한 포인터를 받았기 때문에 C 컴파일러는 "bar"가 x를 변경할 수 있는지 여부를 알 수 없습니다.반면 C# 컴파일러는 foo()가 일시적인 참조(에서는 "byref"라고 함)만 받기 때문에 bar()가 x를 변경할 수 없다는 것을 알고 있습니다.NET 용어)를 사용하여 해당 byref의 복사본은 foo()가 반환되는 지점을 지나도 존속할 수 없습니다.

포인터를 전달하면 코드는 pass-by-ref 시멘틱스로 할 수 있는 것과 같은 일을 할 수 있지만 pass-by-ref 시멘틱스는 코드가 하지 않는 일에 대해 더 강력한 보증을 제공할 수 있게 한다.

언급URL : https://stackoverflow.com/questions/33622787/are-pointers-considered-a-method-of-calling-by-reference-in-c

반응형