C 언어의 포인터에 대한 자세한 설명


머리말

포인터는 C 언어에서 매우 중요한 개념이자 C 언어의 중요한 기능입니다. 정확하고 유연하게 사용하면 복잡한 데이터 구조를 효과적으로 표현할 수 있습니다. 메모리 주소를 통해 직접 데이터를 처리하면 프로그램이 단순하고 컴팩트하며 효율적으로 만들어집니다.


1. 포인터의 기본 개념:

컴퓨터에서는 모든 데이터가 메모리에 저장됩니다. 각 저장 단위의 크기는 1바이트입니다. 관리를 용이하게 하기 위해 각 저장 단위에 번호를 매겨야 합니다. 이 숫자가 저장 단위의 "주소"입니다. 각 A 저장소 장치에는 고유한 주소가 있습니다.

포인터를 이해하는 데 있어 두 가지 중요한 점은 다음과 같습니다.

  1. 포인터는 메모리에서 가장 작은 저장단위의 번호, 즉 메모리 주소이다.
  2. 우리가 일반적으로 구어체에서 이야기하는 포인터는 일반적으로 포인터 변수(변수의 메모리 주소 쌍을 저장하는 데 사용됨)를 나타냅니다.

여기에 이미지 설명을 삽입하세요.
&(주소 연산자)를 통해 변수의 주소를 얻어 포인터 변수에 저장할 수 있습니다.

#include <stdio.h>
int main()
{
    
    
	int a = 10;//在内存中开辟一处空间
	printf("%d", a);//运行结果为10
	int* p = &a;//这里取出变量a的地址,放到指针变量p中
	*p = 20;//通过对p解引用找到a来修改a的值
	printf("%d", a);//运行结果为20
	return 0;
}

포인터에 대한 이해를 강화하기 위해 예를 들어 보겠습니다.
여기에 이미지 설명을 삽입하세요.
예를 들어 a가 호텔에 체크인하는 경우 a를 찾으려면 방별로 검색해야 합니다. 효율성이 크게 저하됩니다. 가장 좋은 방법은 객실번호를 통해 찾는 것이 정확하고 효율적입니다. 여기의 거주자는 변수 a에 해당하고, 방번호는 a의 메모리 주소이며, 주소를 역참조하여 a를 찾을 수 있습니다.

포인터 변수는 몇 바이트를 차지합니까?

  • 32비트 머신에서 주소는 32개의 0 또는 1로 구성된 이진 시퀀스이며 주소는 4바이트의 공간에 저장되어야 하므로 포인터 변수의 크기는 4바이트가 되어야 합니다.
  • 마찬가지로 64비트 시스템을 사용하는 경우 주소를 저장하려면 포인터 변수의 크기가 8바이트여야 합니다.

참고: 포인터 변수의 크기는 저장된 데이터의 유형과 관련이 없으며 동일한 환경에서 포인터 변수의 크기는 동일합니다.

2. 포인터 유형:

우리 모두는 변수에 정수, 부동 소수점 등 다양한 유형이 있다는 것을 알고 있습니다. 포인터에 유형이 있습니까?

int main()
{
    
    
	int* p1 = NULL;//NULL是空指针
	char* p2 = NULL;
	float* p3 = NULL;
	return 0;
}

위 코드를 보면 다음 사항을 알 수 있습니다.포인터는 유형+로 정의됩니다.*.

예를 들어:

  • int 유형 포인터는 int* 유형 변수의 주소를 저장하는 데 사용됩니다. 아>
  • char 유형 포인터는 char* 유형 변수의 주소를 저장하는 데 사용됩니다. 아>
  • float 유형 포인터는 float* 유형 변수의 주소를 저장하는 데 사용됩니다. 아>

그렇다면 이 정의의 의미는 무엇입니까?

1. 포인터 ± 정수:

#include <stdio.h>
int main()
{
    
    
	char a = 'a';
	char* pa = &a;
	int b = 10;
	int* pb = &b;
	printf("%p\n", pa);//0x00D5FEBB
	printf("%p\n", pa + 1);//0x00D5FEBC
	printf("%p\n", pb);//0x00D5FED0
	printf("%p\n", pb + 1);//0x00D5FED4
	return 0;
}

위 코드를 실행한 결과를 살펴보세요.

  • char*+1 유형의 변수는 주소를 1바이트씩 증가시킵니다.
  • int*+1 유형의 변수 주소는 4바이트씩 증가합니다.

요약: 포인터의 유형에 따라 한 단계 앞으로 및 뒤로 이동하는 거리(거리)가 결정됩니다.

2. 포인터 역참조:

#include <stdio.h>
int main()
{
    
    
	int n = 0x11223344;
	char* p1 = (char*)&n;//将n地址强制转化为char*类型
	int* p2 = &n;
	*p1 = 0;//n变为0x11223300
	*p2 = 0;//n变为0x00000000
	return 0;
}

요약하다:

  • 포인터 변수의 유형은 역참조 시 권한의 정도(조작할 수 있는 바이트 수)를 결정합니다.
  • 예를 들어 char의 포인터 역참조는 1바이트에만 액세스할 수 있는 반면 int는 4바이트에 액세스할 수 있습니다.

3. 포인터 연산:

1. 포인터 ± 정수:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p = &arr[0];
	printf("%d\n", *p);//结果为1
	printf("%d\n", *(p + 1));//结果为2
	return 0;
}

2. 포인터 - 포인터:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	printf("%d", p2 - p1);
	//运行结果为1,说明p2和p1之间有1个变量
	return 0;
}

여기에 이미지 설명을 삽입하세요.

3. 포인터에 대한 관계 연산:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	int* p1 = &arr[0];
	int* p2 = &arr[1];
	if (p2 > p1)//指针的比较
	{
    
    
		printf("yes");//运行结果为yes
	}
	return 0;
}

표준 규정:

배열 요소에 대한 포인터는 배열의 마지막 요소 뒤의 메모리 위치에 대한 포인터와 비교할 수 있지만 첫 번째 요소 앞의 메모리 위치에 대한 포인터와 비교할 수는 없습니다.

4. 포인터와 배열:

#include <stdio.h>
int main()
{
    
    
	int arr[5] = {
    
     1,2,3,4,5 };
	printf("%p", arr);//00F3CC00
	printf("%p", &arr[0]);//00F3CC00
	//可以看到数组名和数组首元素地址是一样的
	return 0;
}

결론: 배열 이름은 배열의 첫 번째 요소의 주소를 나타냅니다. (2가지 경우 제외)

두 가지 상황:

  1. 배열 이름은 sizeof(arr)와 같이 sizeof 내부에 있으며, 배열 이름은 전체 배열을 나타냅니다.
  2. &arr, 이때 배열 이름도 전체 배열을 나타냅니다.

5. 보조 포인터:

포인터 변수도 변수입니다. 변수에는 당연히 주소가 있습니다. 보조 포인터는 포인터 주소를 저장합니다.

#include <stdio.h>
int main()
{
    
    
	int a = 10;
	int* pa = &a;//pa存放a的地址
	int** ppa = &pa;//ppa存放pa的地址
	**ppa = 20;//把a的值改成了20
	int b = 30;
	*ppa = &b;//相当于pa中存了b的地址
	return 0;
}

6. 포인터 배열:

포인터 배열은 배열인가요, 포인터인가요? ?
대답은 배열입니다. 포인터 변수를 저장하는 배열입니다
정수 배열은 정수를 저장하고 문자 배열은 문자를 저장한다는 것을 알고 있습니다.
포인터 배열은 자연스럽게 포인터 변수를 저장합니다.
여기에 이미지 설명을 삽입하세요.


포인터는 양날의 검입니다. 잘 사용하면 프로그래밍이 더 효율적입니다. 잘못 사용하면 프로그램 오류가 많이 발생합니다. 따라서 C 언어를 배우는 모든 사람이 포인터를 잘 배우는 것이 중요합니다!
위 내용은 예비 지침 내용이며, 이제 막 이 블로그를 읽으신 분들께 도움이 되기를 바랍니다.

추천

출처blog.csdn.net/weixin_61661271/article/details/124558398