[임베디드 C 언어] C 언어 포인터 변수 예시

본 블로그 포스팅은 C언어 포인터 변수 그림 으로 재현되어 있으며, 침해된 내용이 있을 경우 연락주시면 빠른 시일 내에 삭제하도록 하겠습니다.

1. C 언어 포인터 변수 다이어그램

1 포인터 변수의 기본 연산기본 연산

    int a,*iptr,*jptr,*kptr;
    iptr = &a;
    jptr = iptr;
    *jptr = 100;
    kptr = NULL;

삽화:

그림

1.1 자기 주소와 자기 공간

포인터 변수도 메모리 공간과 메모리 주소에 해당하는 변수이며, 포인터 이름이 주소이다. 여유 메모리 공간은 얼마나 되나요? 기계어(machine word), 32비트 CPU 및 운영 체제는 32비트, 4바이트이며 해당 값 범위는 0x-0xFFFFFFFF. 64비트 CPU 및 운영 체제는 64비트, 8바이트이며 해당 값 범위는 0x-0xFFFFFFFFFFFFFFFF.

1.2 자기가치, 다른 주소, 다른 공간

포인터 변수의 값은 그것이 가리키는 공간의 주소이고, 주소가 가리키는 공간의 크기는 포인터 변수가 가리키는 타입의 크기이다.

1.3 선언 및 초기화

초기화 없이 포인터 변수를 선언하는 경우 포인터 변수는 자신의 메모리 공간만 확보할 뿐 포인터가 아직 결정되지 않은 상태이므로, 이때 포인터 변수를 lvalue로 역참조하는 것은 불법적인 작업입니다. 포인터 변수 역참조를 lvalue로 사용하려는 경우 세 가지 방법이 있습니다.

int *ptr;
    int *ptr_2;
    int a = 1;
    ptr_2 = &a;
    // *ptr = 0;    // 非法操作,其指向其指向的内存空间还未确定
    ptr = &a;                       // ① 右值是一个变量地址
    ptr = ptr_2;                    // ② 右值是一个同类型指针,且已初始化
    ptr = (int*)malloc(sizeof(int));// ③ 右值是一个内存分配函数返回一个void指针
    *ptr = 0;       // 合法操作,ptr有了确定的指向及指向的内存空间;

1.4 함수 간 포인터 값 전달

함수 (아래 예 a funcForSpace())에 정의된 지역 변수(아래 예 a)는 함수의 스택 프레임에 저장되며, 하나의 함수가 실행된 후 다른 함수(아래 예의 stackFrame_reuse())가 실행되며, stackFrame_reuse()를 반복적으로 사용하면 a가 사용하는 공간이 더 이상 존재하지 않으므로 포인터 변수가 지역 변수의 메모리 공간을 가리키는 경우 해당 주소 값이 전달될 때 유효한 값이 아닙니다. 호출 기능.

#include <stdio.h>

void funcForSpace(int **iptr) {
    
    
    int a = 10;
    *iptr = &a;
}
void stackFrame_reuse()
{
    
    
    int a[1024] = {
    
    0};
}
int main()
{
    
    
    int *pNew;
    funcForSpace(&pNew);
    printf("%d\n",*pNew); // 10,此时栈帧还未被重复使用
    stackFrame_reuse();
    printf("%d\n",*pNew); // -858993460,垃圾值
    while(1);
    return 0;
}

funcForSpace()힙 메모리 조각을 할당하고 이를 호출 함수에 전달할 수 있습니다 .

#include <stdio.h>
#include <malloc.h>
int g(int **iptr) { // 当试图修改主调函数的一级指针变量时,被调函数的参数是一个二级指针
    if ((*iptr = (int *)malloc(sizeof(int))) == NULL)
        return -1;
}
int main()
{
    int *jptr;
    g(&jptr);
    *jptr = 10;
    printf("%d\n",*jptr); // 10
    free(jptr);
    while(1);
    return 0;
}

위 코드 포인터의 전송 프로세스를 설명할 수 있습니다.

그림

다음 다이어그램 a는 컴퓨터 메모리를 나타내고 b는 함수가 호출될 때 스택에서 열리는 스택 프레임 공간을 나타냅니다.

그림

2. 포인터 변수 및 배열 이름

배열 이름은 다음과 같은 포인터 산술 연산을 용이하게 하기 위해 특정 컨텍스트에서 배열의 첫 번째 요소를 가리키는 주소로 변환됩니다.

#include <stdio.h>

int main()
{
    
    
    int a[5] = {
    
    0}; 
    char b[20] = {
    
    0};
    *(a+3) = 10;    // a+3是指相对于地址a,偏移sizeof(int)个字节
    *(b+3) = 'x';   // b+3是指相对于地址b,偏移sizeof(char)个字节

    printf("%d, %c\n",a[3],b[3]); // 10, x
    while(1);
    return 0;
}

위 코드 포인터의 오프셋 세부 정보를 설명할 수 있습니다.

그림

3. 호출 함수와 호출 함수 간의 포인터 전송

다음 코드를 보세요:

#include <stdio.h>
void swap1(int x, int y) {
    
    
    int tmp;
    tmp = x; x = y; y = tmp;
}
void swap2(int *x, int *y) {
    
    
    int tmp;
    tmp = *x; *x = *y; *y = tmp;
}
void caller()
{
    
    
    int a = 10;
    int b = 20;
    swap1(a,b);
    printf("%d %d\n",a,b);
    swap2(&a,&b);
    printf("%d %d\n",a,b);
}
int main()
{
    
    
    caller();
    return 0;
}

위의 코드는 다음 다이어그램을 통해 이해할 수 있습니다.

swap1은 다음 값을 전달합니다.

이미지-20230920100416364

swap2 주소 전송(포인터 전송):

이미지-20230920100424447

4. 함수 매개변수로 배열#

2차원 배열은 배열의 배열이고, n차원 배열은 n-1차원 배열의 배열입니다. 메모리는 1차원 바이트 시퀀스입니다. 소위 n차원 배열은 실제로는 논리적 표현일 뿐이며 물리적 구조는 여전히 1차원 선형입니다.

n차원 배열의 요소는 n-1차원 배열입니다. 포인터가 n차원 배열을 가리키는 데 사용되는 경우 포인터 유형은 함수 매개변수로 사용되는 경우에도 n-1차원 길이 정보를 가져야 합니다.

void g(int a[][2]) {
    
     // void g(int(*a)[2]){是相同写法
    a[2][0] = 5;
}
void caller()
{
    
    
    int a[3][2];
    int (*p)[2] = a;
    *(*(p+2)+0) = 7; // p=2表示相对于地址p偏移sizeof(*p)
    printf("%d\n",a[2][0]);  // 7
    g(a);
    printf("%d\n",a[2][0]); //  5
}

다음 다이어그램을 사용하면 다음 코드를 이해할 수 있습니다.

이미지-20230920100448009

참고:Kyle Loudon《Mastering Algorithms with C》

Supongo que te gusta

Origin blog.csdn.net/qq_39217004/article/details/133068049
Recomendado
Clasificación