[c] C의 포인터 : 앰퍼샌드와 별표를 언제 사용해야합니까?

포인터로 시작하고 약간 혼란 스럽습니다. 나는 &변수의 주소를 의미 *하며 포인터 변수가 가리키는 포인터의 값을 얻기 위해 포인터 변수 앞에 사용될 수 있습니다. 그러나 배열, 문자열로 작업하거나 변수의 포인터 복사본으로 함수를 호출 할 때 상황이 다르게 작동합니다. 이 모든 것 안에 논리 패턴을보기가 어렵습니다.

언제 사용해야 &하고 *?



답변

포인터와 값이 있습니다 :

int* p; // variable p is pointer to integer type
int i; // integer value

다음을 사용하여 포인터를 값으로 바꿉니다 *.

int i2 = *p; // integer i2 is assigned with integer value that pointer p is pointing to

다음을 사용하여 값을 포인터로 바꿉니다 &.

int* p2 = &i; // pointer p2 will point to the address of integer i

편집 : 배열의 경우 포인터와 매우 유사하게 취급됩니다. 그것들을 포인터로 생각하면 *위에서 설명한대로 그 안의 값을 얻는 데 사용 하지만 []연산자를 사용하는 또 다른 더 일반적인 방법도 있습니다 .

int a[2];  // array of integers
int i = *a; // the value of the first element of a
int i2 = a[0]; // another way to get the first element

두 번째 요소를 얻으려면 :

int a[2]; // array
int i = *(a + 1); // the value of the second element
int i2 = a[1]; // the value of the second element

따라서 []인덱싱 연산자는 특수한 형식의 *연산자이며 다음과 같이 작동합니다.

a[i] == *(a + i);  // these two statements are the same thing


답변

배열과 함수를 다룰 때 패턴이 있습니다. 처음에는 조금보기 힘들다.

배열을 다룰 때 다음을 기억하는 것이 유용합니다. 대부분의 상황에서 배열식이 나타날 때 식의 유형은 암시 적으로 “T의 N- 요소 배열”에서 “포인터에서 T”로 변환되고 그 값이 설정됩니다 배열의 첫 번째 요소를 가리 킵니다. 이 규칙의 예외는 배열 표현식이 &또는 sizeof연산자 의 피연산자로 표시되거나 선언에서 초기화 자로 사용되는 문자열 리터럴 인 경우입니다.

따라서 배열 식을 인수로 사용하여 함수를 호출하면 함수가 배열이 아닌 포인터를받습니다.

int arr[10];
...
foo(arr);
...

void foo(int *arr) { ... }

따라서 “% s”에 해당하는 인수에 연산자를 사용 하지 않는 이유는 다음 &scanf()같습니다.

char str[STRING_LENGTH];
...
scanf("%s", str);

암시 적 변환 으로 인해 배열 의 시작을 가리키는 값을 scanf()받습니다 . 이는 배열 표현식을 인수로 호출 한 함수 ( 함수 및 함수 등)에 해당됩니다. char *strstr**scanf*printf

실제로 다음과 같이 &연산자를 사용하여 배열 표현식으로 함수를 호출하지 않을 것입니다 .

int arr[N];
...
foo(&arr);

void foo(int (*p)[N]) {...}

이러한 코드는 흔하지 않습니다. 함수 선언에서 배열의 크기를 알아야하며 함수는 특정 크기의 배열에 대한 포인터에서만 작동합니다 (T의 10 요소 배열에 대한 포인터는 11 요소 배열에 대한 포인터와 다른 유형입니다) T).

배열 표현식이 &연산자 의 피연산자로 나타나는 경우 결과 표현식의 유형은 “T의 N- 요소 배열에 대한 포인터”또는 T (*)[N]이며, 이는 포인터 배열 ( T *[N]) 및 기본 유형에 대한 포인터 ( T *).

함수와 포인터를 다룰 때 기억해야 할 규칙은 다음과 같습니다. 인수 값을 변경하고 호출 코드에 반영하려면 수정하려는 항목에 포인터를 전달해야합니다. 다시 말하지만, 배열은 약간의 멍키 렌치를 작동에 넣지 만 일반적인 경우를 먼저 처리합니다.

C는 모든 함수 인수를 값으로 전달 합니다 . 공식 매개 변수는 실제 매개 변수의 값 사본을 수신하며 공식 매개 변수의 변경 사항은 실제 매개 변수에 반영되지 않습니다. 일반적인 예는 스왑 함수입니다.

void swap(int x, int y) { int tmp = x; x = y; y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);

다음과 같은 결과가 나타납니다.

스왑 전 : a = 1, b = 2
스왑 후 : a = 1, b = 2

형식 매개 변수 x와는 y별개의 개체 ab변경 있도록, x그리고이 y에 반영되지 않습니다 ab. aand 의 값을 수정하고자하므로 스왑 함수에 대한 포인터b전달해야합니다 .

void swap(int *x, int *y) {int tmp = *x; *x = *y; *y = tmp; }
...
int a = 1, b = 2;
printf("before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("after swap: a = %d, b = %d\n", a, b);

이제 출력은

스왑 전 : a = 1, b = 2
스왑 후 : a = 2, b = 1

swap 함수에서 xand 의 값을 변경하지 않고 ywhat xy point 의 값을 변경합니다 . 글을 *x쓰는 것은 글을 쓰는 것과 다릅니다 x. 우리는 값 x자체를 업데이트하지 않고 위치를 가져와 해당 위치 x의 값을 업데이트합니다.

포인터 값을 수정하려는 경우에도 마찬가지입니다. 우리가 쓰면

int myFopen(FILE *stream) {stream = fopen("myfile.dat", "r"); }
...
FILE *in;
myFopen(in);

우리는 입력 매개 변수의 값을 수정하고 stream,하지 무엇을 stream 가리키는 때문에 변경 stream의 값에 영향을주지 않습니다 in; 이것이 작동하려면 포인터에 대한 포인터를 전달해야합니다.

int myFopen(FILE **stream) {*stream = fopen("myFile.dat", "r"); }
...
FILE *in;
myFopen(&in);

다시 말하지만, 배열은 약간의 원숭이 렌치를 작품에 넣습니다. 배열 표현식을 함수에 전달할 때 함수가받는 것은 포인터입니다. 배열 첨자 정의 방법에 따라 배열에서 첨자 연산자를 사용하는 것과 같은 방식으로 포인터에 첨자 연산자를 사용할 수 있습니다.

int arr[N];
init(arr, N);
...
void init(int *arr, int N) {size_t i; for (i = 0; i < N; i++) arr[i] = i*i;}

배열 객체는 할당되지 않을 수 있습니다. 즉, 당신은 같은 것을 할 수 없습니다

int a[10], b[10];
...
a = b;

따라서 배열에 대한 포인터를 다룰 때주의해야합니다. 같은

void (int (*foo)[N])
{
  ...
  *foo = ...;
}

작동하지 않습니다.


답변

간단히 말해서

  • &address-of를 의미하므로 C에서와 같이 매개 변수를 수정하는 함수의 자리 표시 자에서 매개 변수는 참조로 전달하는 앰퍼샌드 수단을 사용하여 값으로 전달됩니다.
  • *는 포인터 변수 의 역 참조 를 의미하며, 이는 해당 포인터 변수의 값을 얻는 것을 의미합니다.
int foo(int *x){
   *x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(&y);  // Now y is incremented and in scope here
   printf("value of y = %d\n", y); // output is 6
   /* ... */
}

위의 예제는 foopass-by-reference를 사용하여 함수를 호출하는 방법을 보여줍니다.

int foo(int x){
   x++;
}

int main(int argc, char **argv){
   int y = 5;
   foo(y);  // Now y is still 5
   printf("value of y = %d\n", y); // output is 5
   /* ... */
}

역 참조 를 사용하는 예는 다음과 같습니다.

int main(int argc, char **argv){
   int y = 5;
   int *p = NULL;
   p = &y;
   printf("value of *p = %d\n", *p); // output is 5
}

위는 주소 y 를 가져 와서 포인터 변수에 할당 한 방법을 보여줍니다 p. 다음 우리는 역 참조 p 첨부하여 *값을 얻기 위해 그 전면 p, 즉 *p.


답변

*C / C ++에서 여러 가지 다른 용도로 사용 되므로 상당히 복잡 할 수 있습니다 .

경우 *이미 선언 된 변수 / 함수 앞에 표시, 그것도 것을 의미한다 :

  • a) *해당 변수의 값에 액세스 할 수 있습니다 (해당 변수의 유형이 포인터 유형이거나 *연산자에 과부하가 걸린 경우 ).
  • b) *곱하기 연산자의 의미를 가지며,이 경우 왼쪽에 다른 변수가 있어야합니다.*

경우 *변수 또는 함수 선언 나타난다는 그 변수 포인터 것을 의미

int int_value = 1;
int * int_ptr; //can point to another int variable
int   int_array1[10]; //can contain up to 10 int values, basically int_array1 is an pointer as well which points to the first int of the array
//int   int_array2[]; //illegal, without initializer list..
int int_array3[] = {1,2,3,4,5};  // these two
int int_array4[5] = {1,2,3,4,5}; // are identical

void func_takes_int_ptr1(int *int_ptr){} // these two are identical
void func_takes int_ptr2(int int_ptr[]){}// and legal

경우 &변수 또는 함수 선언에 나타나는, 일반적으로 그 변수는 그 유형의 변수에 대한 참조임을 의미한다.

경우 &이미 선언 된 변수의 앞에 나타납니다, 그 변수의 주소를 반환

또한 배열을 함수에 전달할 때 배열이 0으로 끝나는 cstring (char 배열)과 같은 경우를 제외하고는 항상 해당 배열의 배열 크기도 전달해야합니다.


답변

포인터 변수 또는 함수 매개 변수를 선언 할 때는 *를 사용하십시오.

int *x = NULL;
int *y = malloc(sizeof(int)), *z = NULL;
int* f(int *x) {
    ...
}

주의 : 선언 된 각 변수에는 고유 한 *가 필요합니다.

값의 주소를 가져 오려면 &를 사용하십시오. 포인터로 값을 읽거나 쓰려면 *를 사용하십시오.

int a;
int *b;
b = f(&a);
a = *b;

a = *f(&a);

배열은 보통 포인터처럼 취급됩니다. 함수에서 배열 매개 변수를 선언하면 포인터임을 쉽게 선언 할 수 있습니다 (같은 의미). 배열을 함수에 전달하면 실제로 첫 번째 요소에 포인터를 전달합니다.

함수 포인터는 규칙을 따르지 않는 유일한 것입니다. &를 사용하지 않고 함수의 주소를 사용할 수 있으며 *를 사용하지 않고 함수 포인터를 호출 할 수 있습니다.


답변

내가 그렇게 대신 rescue.Here에 대한 뉴 사우스 웨일즈 대학에서 비디오로 전환하는 모든 말의 설명을 통해보고 된 간단한 설명은 다음과 같습니다 우리는 주소가있는 셀이있는 경우 x와 가치를 7값의 주소를 요청하는 간접 방법 7입니다 &7및 간접 방법은 주소 값을 요청하는 x것입니다 *x낭포 (cell: x , value: 7) == (cell: &7 , value: *x)그것으로 보는 .Another 방법은 : John에 앉아 7th seat국지적 *7th seat를 가리 킵니다 John&John줄 것이다 address/의 위치를 7th seat. 이 간단한 설명은 저에게 도움이되었고 다른 사람들에게도 도움이 되길 바랍니다. 훌륭한 비디오에 대한 링크는 다음과 같습니다 . 여기를 클릭하십시오.

또 다른 예는 다음과 같습니다.

#include <stdio.h>

int main()
{
    int x;            /* A normal integer*/
    int *p;           /* A pointer to an integer ("*p" is an integer, so p
                       must be a pointer to an integer) */

    p = &x;           /* Read it, "assign the address of x to p" */
    scanf( "%d", &x );          /* Put a value in x, we could also use p here */
    printf( "%d\n", *p ); /* Note the use of the * to get the value */
    getchar();
}

애드온 : 포인터를 사용하기 전에 항상 초기화 하십시오. 그렇지 않으면 포인터가 무엇이든 가리켜 서 운영 체제에서 소유하지 않은 메모리에 액세스하지 못하게되므로 프로그램이 중단 될 수 있습니다. p = &x;, 포인터에 특정 위치를 할당합니다.


답변

실제로, 당신은 그것을 가볍게 두드려서 더 이상 알아야 할 것이 없습니다 🙂

다음 비트를 추가합니다.

  • 두 동작은 스펙트럼의 반대쪽 끝입니다. &변수를 *가져와 주소를 제공 하고 주소를 가져와 변수 (또는 내용)를 제공합니다.
  • 함수에 전달할 때 포인터를 “degrade”합니다.
  • 실제로 간접적으로 여러 레벨을 가질 수 있습니다 ( char **p즉, p에 대한 포인터 임을 의미합니다 char.

다르게 작동하는 것에 대해서는 실제로는 아닙니다.

  • 이미 언급했듯이 배열은 함수에 전달 될 때 포인터 (배열의 첫 번째 요소)로 저하됩니다. 그들은 크기 정보를 보존하지 않습니다.
  • C에는 문자열이 없으며 일반적으로 문자 배열은 일반적으로 영 ( \0) 문자로 끝나는 문자열을 나타냅니다 .
  • 변수의 주소를 함수에 전달하면 포인터 자체를 역 참조하여 변수 자체를 변경할 수 있습니다 (일반적으로 변수는 값을 기준으로 전달됩니다 (배열 제외)).