본 블로그 포스팅은 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은 다음 값을 전달합니다.
swap2 주소 전송(포인터 전송):
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
}
다음 다이어그램을 사용하면 다음 코드를 이해할 수 있습니다.
참고:Kyle Loudon《Mastering Algorithms with C》