programing

C의 함수 인수로 포인터

mailnote 2023. 10. 28. 08:07
반응형

C의 함수 인수로 포인터

예를 들어 다음과 같은 코드를 사용할 수 있습니다.

int num = 5;
int *ptr = #

다음 두 기능의 차이점은 무엇입니까?

void func(int **foo);
void func(int *foo); 

함수를 호출하는 위치:

func(&ptr); 

둘 중 하나는 포인터를 매개 변수로 사용하고, 두 번째는 포인터만 사용한다는 것을 알고 있습니다.

지나가면func(&ptr), 저는 효과적으로 포인터를 보내고 있습니다.포인터가 다른 포인터를 가리킨다면 어떤 차이가 있습니까?

후자가 비호환성 경고를 할 것으로 생각하지만, 당신이 무엇을 하고 있는지 알기만 하면 세부 사항은 중요하지 않은 것 같습니다.가독성과 전자를 이해하기 위해서 더 나은 선택지(2성 포인터)인 것 같지만 논리적인 관점에서 보면 어떤 차이가 있습니까?

사용자가 정확하게 전달된 내용을 변경할 수 없다는 것이 합리적인 경험칙입니다. 이는 발신자가 변경 내용을 보는 방식입니다.포인터를 전달하는 것이 해결책입니다.

:void fcn(int foo)

값을 전달하면 값의 복사본을 얻을 수 있습니다.함수의 값을 변경해도 호출자는 변경 내용에 관계없이 원래 값을 볼 수 있습니다.

포인터를 값으로 전달:void fcn(int* foo)

포인터를 지나가면 포인터의 복사본이 나타납니다. 포인터는 원본과 동일한 메모리 위치를 가리킵니다.이 메모리 위치는 원본이 저장되는 위치입니다.이렇게 하면 포인투 값을 변경할 수 있습니다.그러나 포인터 복사본만 받았기 때문에 실제 포인터를 데이터로 변경할 수는 없습니다.

포인터를 값에 포인터 전달:void fcn(int** foo)

포인터를 값에 대한 포인터로 전달하면 위의 내용을 이해할 수 있습니다.위와 같이 발신자 코드가 사용하고 있는 메모리 위치와 동일하므로 발신자가 변경 내용을 볼 수 있도록 값을 변경할 수 있습니다.같은 이유로 포인터를 값으로 변경할 수 있습니다.이를 통해 함수 내에 메모리를 할당하고 반환하는 등의 작업을 수행할 수 있습니다.&arg2 = calloc(len); 복사본을 받기 때문에 포인터를 포인터로 변경할 수는 없습니다.

프로세서가 코드를 처리할 때 차이점은 간단히 말해집니다.가치 자체는 두 경우 모두 주소일 뿐입니다. 사실입니다.그러나 주소가 역참조됨에 따라 프로세서와 컴파일러 모두가 역참조 후 무엇을 처리할 것인지 아는 것이 중요합니다.

예를 들어 다음과 같은 코드를 사용할 수 있습니다.

int num = 5;
int *ptr = #

다음 두 기능의 차이점은 무엇입니까?

void func(int **foo);
void func(int *foo);

첫번째는 int를 가리키는 포인터를 원하고, 두번째는 int를 직접 가리키는 포인터를 원합니다.

함수를 호출하는 위치:

func(&ptr);

~하듯이ptr인트를 가리키는 지시자입니다&ptr주소이며, A와 호환됩니다.int **.

a를 취하는 함수는int *와 같이 뭔가 다른 일을 할 것입니다.int **되지 않은 할 수 대화의 결과가 완전히 달라져서 정의되지 않은 행동으로 이어지거나 충돌이 발생할 수 있습니다.

func(&ptr)를 통과하면 포인터를 효과적으로 통과합니다.포인터가 다른 포인터를 가리킨다면 어떤 차이가 있습니까?

               +++++++++++++++++++
adr1 (ptr):    +  adr2           +
               +++++++++++++++++++

               +++++++++++++++++++
adr2 (num):    +  42             +
               +++++++++++++++++++

앳.adr2, 42달러의 내재가치가 있습니다.

앳.adr1, 우리는 주소를 가지고 있습니다.adr2, 포인터만 한 크기의

&ptr우리에게 dr1을 주고,ptr, 가치가 있습니다.&num은 dr2 .

사용하면adr1int *,adr2정수로 잘못 처리되어 (possibly가 상당히 큰) 숫자로 이어집니다.

사용하면adr2int **, 첫 번째 참조 해제는 42로 이어지는데, 이는 주소로 잘못 interpre되어 프로그램이 중단될 가능성이 있습니다.

그것은 단지 광학적인 것 이상의 차이를 가지는 것입니다.int *그리고.int **.

후자가 위화감 경고를 할 것이라고 생각합니다.

... 그 뜻은...

하지만 당신이 뭘 하고 있는지 알기만 하면 세부사항은 중요하지 않은 것 같습니다.

그러니?

가독성과 전자를 이해하기 위해서 더 나은 선택지(2성 포인터)인 것 같지만 논리적인 관점에서 보면 어떤 차이가 있습니까?

그것은 기능이 포인터로 무엇을 하느냐에 따라 달라집니다.

실무적으로 크게 두 가지 차이점이 있습니다.

  1. 포인터를 포인터에 전달하면 호출자가 볼 수 있는 방식으로 해당 포인터의 내용을 수정할 수 있습니다.고전적인 예는 두번째 주장입니다.strtol(). 에 전화를 걸면 다음으로strtol(), 해당 포인터의 내용은 계산하기 위해 구문 분석되지 않은 문자열의 첫 번째 문자를 가리켜야 합니다.long value로 요. 만약 당신이 그 포인터를 그냥 넘겨줬다면.strtol(), 그러면 변경 사항은 로컬이 될 것이고, 발신자에게 위치를 알리는 것은 불가능할 것입니다.그 포인터의 주소를 넘기면strtol()호출자가 볼 수 있는 방식으로 수정할 수 있습니다.다른 변수의 주소를 전달하는 것과 같습니다.

  2. 더 근본적으로, 컴파일러는 참조를 해제하기 위해 가리키는 유형을 알아야 합니다.예를 들어, 재참조할 때 a.double *, 컴파일러가 해석할 것입니다. (다음과 같은 구현에 대해)double8바이트를 소비합니다) 메모리 위치에서 시작하는 8바이트를 두 배의 값으로 사용합니다.하지만 32비트 구현에서, 재참조할 때,double **, 컴파일러는 그 위치에서 시작하는 4바이트를 다른 두 배의 주소로 해석할 것입니다.포인터를 재참조할 때 해당 주소에서 데이터를 해석하는 방법에 대해 컴파일러가 가진 정보는 포인터가 가리키는 유형뿐이므로 정확한 유형을 아는 것이 중요하며, 이 때문에 "모두 포인터일 뿐인데 뭐가 다를까?"라고 생각하면 오류가 발생합니다.

일반적으로 이 차이는 함수가 포인터에 할당된다는 것을 의미하며, 이 할당은 함수에만 로컬로 적용되어서는 안 됩니다.예를 들어, (그리고 이 예들은 완전한 기능이 아닌 음식의 특성을 조사하기 위한 것이며, 원래 게시물의 코드가 실제 작동 코드인 것으로 간주되는 것 이상의 것임을 명심하십시오.)

void func1 (int *foo) {
    foo = malloc (sizeof (int));
}

int a = 5;
func1 (&a);

와 비슷합니다.

void func2 (int foo) {
    foo = 12;
}

int b = 5;
func2 (b);

그런 의미에서foofunc2 (),에서는 12와 같을 수 있지만 func2 ()이 돌아오면,b5와 같아질 겁니다func1()에서,foo새로운 int를 가리키지만,a아직은afunc1 ()이 돌아올 때.

만약 우리가 그 가치를 바꾸고 싶다면?a아니면b? WRTb, 정규 int:

void func3 (int *foo) {
    *foo = 12;
}    

int b = 5;
func2 (&b);

효과가 있을 겁니다. 우리는 int에 대한 포인터가 필요하다는 것을 주목하세요.포인터의 값을 변경합니다(즉,int가 가리키는 주소(Int가 가리키는 값뿐만 아니라 int가 가리키는 주소):

void func4 (int **foo) {
    *foo = malloc (sizeof (int));
}

int *a;
foo (&a);

'a'는 이제 func4에서 malloc에 의해 반환된 기억을 가리킵니다.주소를&a주소는a, 인트를 가리키는int 포인터는 int의 주소를 포함합니다.func4()func3 ()가 int의 주소를 가져가서 새로운 int 값을 넣을 수 있는 것처럼 int의 주소를 이 주소에 넣을 수 있도록 int 포인터의 주소를 가져갑니다.

이렇게 다양한 논증 스타일이 사용됩니다.

이 질문을 받은 지는 꽤 됐지만, 여기에 대한 저의 의견이 있습니다.나는 지금 C를 배우려고 노력중이고 포인터들은 끝없이 혼란스럽습니다...그래서 저는 적어도 저를 위해 포인터에 대한 포인터를 명확히 하기 위해 이 시간을 할애하고 있습니다.제 생각은 이렇습니다.
여기서 예를 들어 보겠습니다.

#include <stdlib.h>
#include <string.h>

int allocstr(int len, char **retptr)
{
    char *p = malloc(len + 1);  /* +1 for \0 */
    if(p == NULL)
        return 0;
    *retptr = p;
    return 1;
}

int main()  
{
    char *string = "Hello, world!";
    char *copystr;
    if(allocstr(strlen(string), &copystr))
        strcpy(copystr, string);
    else    fprintf(stderr, "out of memory\n");
    return 0;
}

allocstr에 더블 포인터가 필요한 이유가 궁금합니다.포인터라면 패스할 수 있으며 반환 후 변경됩니다.
이 예제를 수행하면 잘 작동합니다.그러나 allocstr을 **pointer 대신 *pointer만(및 &copystrin main 대신 copystr만)하도록 변경하면 segmentation fault가 발생합니다. 왜죠?코드에 프린트를 좀 넣었는데 strcpy가 있는 라인까지 잘 작동합니다.그래서 나는 그것이 copystr에 대한 메모리를 할당하지 않았다고 추측합니다.다시 한번, 왜?
포인터로 지나가면 어떤 의미가 있는지 다시 한 번 살펴보도록 하겠습니다.즉, 기억 위치를 지나면 원하는 값을 바로 쓸 수 있습니다.값의 메모리 위치에 액세스할 수 있으므로 값을 수정할 수 있습니다.
마찬가지로 포인터를 포인터에 전달하면 포인터의 메모리 위치, 즉 메모리 위치의 메모리 위치를 전달합니다.이제 포인터만 사용할 때 값을 변경할 수 있으므로 메모리 위치를 변경할 수 있습니다.
코드가 작동하는 이유는 메모리 위치의 주소를 전달하기 때문입니다.함수 allocstr은 "Hello world!"를 유지할 수 있도록 해당 메모리 위치의 크기를 변경하고 해당 메모리 위치에 포인터를 반환합니다.
포인터를 보내는 것과 같지만 값 대신 메모리 위치가 있습니다.

C에서 링크된 구조를 사용하는 경우, 예를 들어 단순 링크된 리스트.목록에 일부 항목이 있고 새 항목을 추가하려는 경우 항목 순서가 중요하지 않을 때 처음에 삽입하는 것이 가장 쉬운 방법입니다.자, 여기 간단한 아이템 구조가 있습니다.

typedef struct {
    char *data;    /* item data */
    struct item *next;    /* point to successor */
} item;

그리고 맨 앞에 삽입하면,

void insert_item( item **head, char *data) {

    item *new_item;    /* temporary pointer */

    new_item = malloc( sizeof(item) );
    new_item->data = data;

    /* This is how we would set the next item if the parameter was item* head */
    //new_item->next = head;

    /* till this line, nothing useful for passing item** head */
    new_item->next = *head;

    /*
     * Here is where we needed to update the head to point to the newly inserted item at
     * the beginning. which wouldn't be possible if the head parameter was item* head.
     */
    *head = new_item;
}

이렇게 테스트를 할 수 있습니다.

item *head;
head = malloc( sizeof(item) );
head->data = "head item data";

printf("before inserting: %s \n", head->data); //before inserting: head item data

insert_item(&head, "new item data");

printf("after inserting: %s \n", head->data); //after inserting: new item data

언급URL : https://stackoverflow.com/questions/18698317/pointers-as-function-arguments-in-c

반응형