반응형

구조체 및 구조체 배열에 관해서는 아래 참고.

https://ansan-survivor.tistory.com/1333

 

[C언어] 구조체(struct)에 배열을 선언하여 사용 방법, 선언과 동시에 초기화

앞서 구조체에 대한 설명이 있다. https://ansan-survivor.tistory.com/1331 [C언어] 구조체(struct) 에 대해서, C언어 구조체란? 구조체 사용방법, 구조체 선언과 동시에 초기화 구조체(struct)란?  - 여러 자료..

ansan-survivor.tistory.com

 

위 구조체를 포인터 형태로 접근하는 방법이다.

 

pos의 자료형은 struct point 이므로 포인터 변수 pptr의 타입도 struct point * 으로 선언했다. 그리고 포인터이므로 pos 구조체의 주소를 넣어주었다.

// 구조체 선언 및 초기화
struct point pos = {11, 12};

// 구조체 인스턴스 pos의 주소를 가리키는 포인터 선언
struct point * pptr = &pos;

 

포인터 변수 선언한 pptr은 아래와 같이 이용한다. 해당 구조체에 값을 넣기 위해

*pptr 으로 구조체에 접근, 연산자 . 마침표를 이용해 구조체 내부의 값 xpos, ypos에 접근하는 방식이다.

(*pptr).xpos = 10;
(*pptr).ypos = 20;

하지만 위 연산자를 아래와 같이 대체할 수 있다. (빨간색 부분을 보면 된다)

(*pptr).xpos  ==  pptr->xpos

pptr->xpos = 10;
pptr->ypos = 20;

 

반응형

 

사용 예제

#include <stdio.h>

struct point
{
	int xpos;
	int ypos;
};

int main()
{
	// 구조체 선언과 동시에 초기화 (2개의 인스턴스 pos1, pos2)
	struct point pos1 = { 1, 2 };
	struct point pos2 = { 100, 200 };

	// pos1인스턴스를 가리키는 포인터 변수 선언
	struct point * pptr = &pos1;

	// pptr이 pos1을 가리키니, pos1으로 접근함
	(*pptr).xpos += 4;
	(*pptr).ypos += 5;
	printf("[%d %d] \n", pptr->xpos, pptr->ypos);


	return 0;
}

해당 주소에 접근해서 더해짐

반응형
반응형

앞서 함수포인터에 관해 설명했다.

함수포인터에서 input 매개변수와 반환형 타입정보가 반드시 들어가야 된다고 설명했다.

https://ansan-survivor.tistory.com/1291

 

[C언어] 함수포인터 (함수형 포인터) 이해하기 예제

C언어의 함수에 관해서는 이전 포스팅에서 설명했다. https://ansan-survivor.tistory.com/1224 [C언어] C언어 함수 만들기, 함수 구조, 함수 템플릿, 함수 작동 순서 C언어 함수의 구조는 [return 타입] 함수명(.

ansan-survivor.tistory.com

 

그러나 함수포인터의 한종류지만, Void포인터는 타입(Type)이 존재하지 않는 Void 포인터 이다!

결론 부터 말하자면 void 포인터는 아래와 같이 선언한다.

 => void * ptr;

 

- void 포인터로 선언한 이 ptr은 그 어떠한 주소값도 다 저장이 가능하다.

- Type정보가 존재하지 않기 때문에 Type을 신경쓰지 않고 해당 주소값을 저장 가능.

- 타입 정보가 존재하지 않아서 을 사용하는 연산은 불가

 

예시)

#include <stdio.h>

/*
	모든 주소값을 저장할 수 있는 void 포인터, (type정보 필요없음, 오직 주소만 저장)
	type(자료형) 이 존재하지 않기 때문에,  *연산은 불가능하다.

	선언방법: void * ptr;
	*ptr = 3.14 ; 이러한 연산은 불가능하다. 왜냐하면, 자료형을 모르기 때문이다.
	ptr++;		  이러한 연산도 불가능하다. 자료형을 몰라서.
*/

// void이므로 return이 필요 없음.
void func(void)
{
	printf("Nothing to do\n");
}

int main()
{
	int num = 20;
	void* ptr;				// void 포인터 선언.

	ptr = &num;				// ptr포인터에 num의 주소값을 저장 (그러나 int형 type은 못따라온다)
	printf("%p \n", ptr);	// ptr이 가리키는 주소값 출력

	ptr = func;				// void 포인터에 함수포인터도 저장이 가능하다!!!!!
	printf("%p \n", &ptr);	//	ptr자체의 주소값.

	return 0;
}
반응형

프로그램을 실행시켜보면 아래와 같다.

특정 값 num의 주소가 저장이 가능하며, 함수인 func( )의 주소 또한 저장이 가능하다.

즉, 타입(type)에 구애받지 않고 어떠한 주소도 다 담을 수 있다. 다시말해 그저 해당 주소를 향해 가리키는 역할만 한다.

(결과)

void * ptr은 그 내부에 타입 상관없이 포인팅 가능.

 

반응형
반응형

C언어의 함수에 관해서는 이전 포스팅에서 설명했다.

https://ansan-survivor.tistory.com/1224

 

[C언어] C언어 함수 만들기, 함수 구조, 함수 템플릿, 함수 작동 순서

C언어 함수의 구조는 [return 타입] 함수명( [input타입 변수명] ) ex)  int  main(  int a  ) 함수명은 말 그대로 함수 이름 지정. input 은 이 함수가 실행되기 위한 입력 값을 지정하는것. return 타입은..

ansan-survivor.tistory.com

 

C언어 함수의 구조는 아래와 같다.

 

[return 타입] 함수명( [input타입 변수명] )

ex)   int   main(   int a   )

 

함수명은 말 그대로 함수 이름 지정.

input 은 이 함수가 실행되기 위한 입력 값을 지정하는것.

return 타입은 이 함수가 연산이되어 return되는 값의 타입.

 

즉 자세히 보면, 2가지의 Type이 선언되어야 한다.

1. input이 되는 값의 타입

2. return되는 인자의 타입


함수는 컴파일시 그 이름 자체로 메모리에 있는 특정 주소값으로 치환된다. 즉 함수 이름자체는 "상수형 포인터"이다.

즉, 함수의 이름 그자체는 실제로 메모리의 특정 주소값 (0x0000)를 가리키고 있는 포인터 이다.

다만 함수이름 포인터는 input인자의 type정보와, return인자의 type정보가 함께 제공되어야 한다. (void가 아니라면)

함수 선언시 메모리의 특정 주소에 포인터로 가리킨다. 이때 input, return 타입정보도 함께 입력된다.

* 함수포인터를 선언하는 방법

1. 함수의 이름은 함수가 저장된 메모리공간을 가리키는 상수형 포인터이다. (함수 이름 자체는 상수형 타입으로 변경 불가)
2. 함수이름의 의미하는 '주소값' 은 "함수 포인터 변수"를 선언해 저장가능. (함수의 주소값을 가리키는 변수 선언 가능)
3. 함수포인터변수를 선언하려면, 사용할 함수의 반환, 매개변수 Type(자료형)을 알아야 한다.

 

아래 예제에서는 2개의 함수를 선언했다.

그리고 

int (*fptr) (int, int);  <= input parameter의 이름은 중요하지 않다. type만 넣으면 된다. (2개가 입력되므로 int, int)
void (*ptrstring) (char*);

두 함수포인터를 선언해서 사용.

#include <stdio.h>

/*
	포인터를 선언하기 위해서는, 주소값과 자료형이 주어져야 하는데, 함수의 이름을 다음과 같이 생각하고 포인터를 선언한다.
	함수 읽기. (함수포인터를 선언하기 위하여)
	ex) int fct(int a );
	1.
		이 함수의 주소값은? fct의 주소. (함수이름 = 주소값)
	2.
		type형은?	"Parameter가 int 이고, return값이 int 이다."
	ex) double Fct (double a , double b );
	1.
		함수의 주소값? 함수이름 Fct 의 주소.
	2.
		type형은?	"Parameter가 2개의 double, return값이 double 이다."
        
	아래 예제에서 선언한 함수포인터변수 2개.
	int (*fptr) (int, int);
	void (*ptrstring) (char *);
*/


int fct(int a, int b)
{
	int c = 0;

	c = a - b;

	return c;
}

void ShowString(char* str)
{
	printf("%s \n", str);
}

int main()
{
	char* str = "ich liebe dich";


	// 함수포인터를 선언하기!!
	// [자료형: 매개변수 int형인, 리턴값이 int형 2개인] 포인터함수 fptr 를 선언!!
	//	함수이름은 의미없다. *만 있으면 될뿐, 그러나 자료형은 반드시 일치해야 한다.
	int(*fptr) (int, int);


	fptr = fct;		//	fptr -> fct의 주소를 가리킴. (함수이름이 주소값이므로)

	// 상수 함수 포인터로 출력
	printf("%d \n", (fct(5, 7)));

	// 변수 함수 포인터로 출력
	printf("%d \n", (fptr(10, 15)));


	// 함수 포인터 선언하기.
	// 자료형: char * (케릭터 포인터형을 매개변수로 받고, return값은 없다)
	void(*ptrstring)(char*);

	// ptrstring -> ShowString함수를 가리킴.
	ptrstring = ShowString;

	ShowString(str);
	ptrstring(str);

	return 0;
}

/*
	fct 는  '상수' 함수포인터 이름이 될 수 있다! (변경 불가)
	fptr 은 '변수' 함수포인터 이름이 될 수 있다! (변경 가능)
*/
반응형

(결과)

받는 인자 int, int 와 출력인자 int 타입인 *fptr 이름의 함수포인터를 선언.

fptr = fct 

위 과정을 아래와 같이 도식화 하면,

함수 fct는 이미 특정 메모리주소에 '상수형포인터' 으로써 저장되고,

함수포인터가 선언되고 그 함수를 인자로 받게 되면, 이제 그 함수를 가리키게 된다.

함수포인터는 '변수형포인터' 으로 동일하게 사용한다.

 

문자열도 마찬가지로 함수포인터를 선언하면 동일하게 사용 가능하다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형
반응형

이전에 변수형 포인터와 상수형 포인터를 설명했다.

배열도 포인터이다. int arr[ ]; 선언이라면, arr 그 이름 자체가 int* 자료형임을 설명했다.

https://ansan-survivor.tistory.com/1249

 

[C언어] C언어 배열과 포인터의 관계 (변수형 포인터, 상수형 포인터), 포인터로 배열 변경하기

포인터에 대한 간단한 설명은 아래 참고. https://ansan-survivor.tistory.com/1237 [C언어] 포인터란? 포인터에 대해 쉽게 이해하기. (포인터 변수 사용하기, 포인터로 값 변경하기, (알아두기) 컴퓨터는 32비

ansan-survivor.tistory.com

 

만약 int * arr[20]; 이라는 선언이 있다.

위 arr 의 자료형은 int** 이다.

int* 와 arr은 상수형 포인터로 만약 int arr[20]; 선언을 했다면 int* 타입이 될 것이다.

고로 앞에 int* 과 상수형 포인터 *가 합쳐져서,

int * arr[20]; 의 자료형은 int* + int* = int** 가 된다.

 

예제)

도식관계를 그려보면 아래와 같다.

#include <stdio.h>

int main()
{
	/*
		아래 ptr1 ~ ptr3 까지의 선언은 선언과 동시에 ptr은 각 num의 주소를 가리킴.
	*/
	int num1 = 10, num2 = 20, num3 = 30;
	int* ptr1 = &num1;
	int* ptr2 = &num2;
	int* ptr3 = &num3;

	// 배열의 내부 인자로 사용할 값의 자료형이 int* 이므로, 배열이름의 자료형은 int* 형이 되어야 함
	int* ptrArr[] = { ptr1, ptr2, ptr3 };
	/*				   
		ptrArr[0] -> ptr1 -> num1
		ptrArr[1] -> ptr2 -> num2
		ptrArr[2] -> ptr3 -> num3
		이런식의 포인터가 선언된 것임.
	*/

	// ptrArr은 기본적으로 *int 자료형이고, 앞에 선언한 자료형이 int* 이므로, ptrArr 자체는 int** 자료형임.
	int** dptr = ptrArr;
	// 배열에 포인터를 선언하여 같은 첫번째 주소값을 공유함. 포인터를 배열 처럼 사용할 수 있다.

	dptr[0] = 10;
	dptr[1] = 20;
	dptr[2] = 30;

	printf("%d %d %d \n", dptr[0], dptr[1], dptr[2]);

	return 0;
}
반응형

배열 내에 포인터값을 사용하기 위해서 선언을 하면, 배열 내부의 각 타입에 맞춰 배열이름의 타입형을 선언해야 함.

배열 내 사용할 인자들의 타입이 int* 이므로,  배열이름의 타입도 int* 이어야 함.

고로 -> int* arrPtr[20]; 이런식의 선언이 이루어짐.

 

배열 내 인자들은 더블포인터 상태임. arrPtr[0] 은 int* + int* 이므로 int** 자료형으로 위 예제처럼 dptr을 선언할 수 있음.

 

 

 

 

반응형
반응형

포인터에 관한해서.

https://ansan-survivor.tistory.com/1237

 

[C언어] 포인터란? 포인터에 대해 쉽게 이해하기. (포인터 변수 사용하기, 포인터로 값 변경하기,

(알아두기) 컴퓨터는 32비트와 64비트를 많이 사용한다. 이는 1번 처리에 사용할 수 있는 메모리의 크기이다. 만약 32비트(4byte) PC라면, 8 byte를 할당해도 저장할 수 있는 공간은 4byte 뿐이다. 나머지

ansan-survivor.tistory.com

 

더블포인터에 관해서.

https://ansan-survivor.tistory.com/1288

 

[C언어] 포인터의 포인터 (더블 포인터, 이중 포인터, 삼중 포인터) 이해하기 예제

앞서 간단하게 포인터란 무엇인지, 예제를 통해 설명. https://ansan-survivor.tistory.com/1237 [C언어] 포인터란? 포인터에 대해 쉽게 이해하기. (포인터 변수 사용하기, 포인터로 값 변경하기, (알아두기)

ansan-survivor.tistory.com

 

더블포인터의 swap 예제.

#include <stdio.h>

/*
	더블포인터 **ptr
	더블 포인터를 이용해 
	swapIntptr 함수 만들기.
	num1 -> num2 값으로,
	num2 -> num1 값으로,
*/

//	주소값의 인자를 받기 위해
//  (*p1)의 자료형 int*, ptr1에 저장하기 위해서는 자료형이 같아야 한다.
void SwapIntPtr(int* * p1, int* * p2)							
{
	int * temp = *p1;	//	*p1 = ptr1 을 의미, ptr1의 주소를 temp에 저장.
	*p1 = *p2;			//	ptr2의 주소를 ptr1에 저장.
	*p2 = temp;			//	*p2 = ptr2 이고, ptr2의 자료형은 (int *) 이므로 temp의 자료형과 같아서 대입 가능.
}

int main()
{
	int num1 = 10, num2 = 20;		
	int * ptr1 = NULL;
	int * ptr2 = NULL;	//	포인터 초기화
	
	ptr1 = &num1, ptr2 = &num2;

	SwapIntPtr(&ptr1, &ptr2);	//	함수를 통해 값을 변경하려면, 그 주소값을 인자로 전달해야함.

	/*
		즉, p1 -> ptr1 -> num1 을 가리키고,
			p2 -> ptr2 -> num2 를 가리킴.
	*/


	printf("num1: %d\n num2: %d \n", *ptr1, *ptr2);

	return 0;
}
반응형

(결과)

 

 

반응형
반응형

앞서 간단하게 포인터란 무엇인지, 예제를 통해 설명.

https://ansan-survivor.tistory.com/1237

 

[C언어] 포인터란? 포인터에 대해 쉽게 이해하기. (포인터 변수 사용하기, 포인터로 값 변경하기,

(알아두기) 컴퓨터는 32비트와 64비트를 많이 사용한다. 이는 1번 처리에 사용할 수 있는 메모리의 크기이다. 만약 32비트(4byte) PC라면, 8 byte를 할당해도 저장할 수 있는 공간은 4byte 뿐이다. 나머지

ansan-survivor.tistory.com

 

보통 일반적으로 많이 사용되는 것은, * 하나만을 사용하는 "싱글포인터"이다.

때로는 필요에 의해 포인터에서 또다른 포인터로 참조를 하는 더블포인터, 또 더 참조하면 트리플포인터 까지 사용된다.

위와 같은 다중포인터에 대한 예제.

 1. double* ptr = &num;  => ptr의 타입은 double* 으로 num의 주소값을 저장.

 2. double* *dptr = &ptr;   => dptr은 double* 타입인 ptr이 대입되므로, *을 하나 더 붙여 double** 으로 만듦

#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);

	return 0;
}

반응형

위와 같은 참조 관계가 구성되어있기 때문에, num의 값을 새로운 포인터변수로 바꿔주면 모두 바뀌게 된다.

새로운 ptr2를 선언해서 num의 주소값을 넣고 값을 5.2를 대입해보기

#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	// 새로운 ptr2선언
	double* ptr2 = NULL;
	ptr2 = &num;
	*ptr2 = 5.2;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);

	return 0;
}

모두 num을 참조하기 때문에 다 바뀌게 되었다.

가리키고 있는 대상의 주소값을 확인하기

#include <stdio.h>

/*
	포인터의 포인터에 대한 이해.
	변수의 주소값을 저장하기 위해서 * 을 추가 하기만 하면 된다.
*/

int main()
{
	double num = 3.14;
	double* ptr = &num;

	// ptr의 타입이 double* 이므로 dptr을 포인터 선언하기 위해서는 *를 더 붙인다.
	double** dptr = &ptr;
	// dptr의 타입이 double** 이므로 tptr을 포인터 선언하기 위해서는* 를 더 붙인다.
	double*** tptr = &dptr;

	// 새로운 ptr2선언
	double* ptr2 = NULL;
	ptr2 = &num;
	*ptr2 = 5.2;

	/*
		위에 포인터의 정의를 통해, (참조관계)
		tptr -> dptr -> ptr -> num  이런식으로 포인터가 가리키고 있다.
	*/
	printf("num값: %f\n", num);
	printf("ptr값: %f\n", *ptr);
	printf("dptr값: %f\n", **dptr);
	printf("tptr값: %f\n", ***tptr);


	// 모두 가리키는 대상은 num의 주소값
	printf("num주소: %9p\n", &num); // ptr은 num의 주소값을 가리킴
	printf("ptr이 가리킴: %9p\n", ptr); // ptr은 num의 주소값을 가리킴
	printf("dptr이 가리킴: %9p\n", *dptr);
	printf("tptr이 가리킴: %9p\n", **tptr);
	
    return 0;
}

모두 한곳을 가리키고 있다.

 

 

포인터 변수 연산 이해 과정.

아래와 같이 괄호를 활용해서 연산 순서를 이해해보면 더 이해를 잘할 수 있다.

 

반응형
반응형

1차원 배열은 열거된 수들이고,

2차원 배열은 row와 column이 있다.

3차원은 마치 정육면체 형태처럼 row와 column에 추가로 높이가 있는 것이다.

3차원 배열은 행과 열 외에도 높이(깊이) 라는 속성이 추가된다.

(1차원 배열)

문자열도 1차원 배열의 한종류이다.

https://ansan-survivor.tistory.com/1251

 

[C언어] 포인터로 문자열 선언, 배열 문자열 선언과 차이. (문자열 내부 변경하기)

문자열(string)이란, 알파벳 하나하나가 메모리상의 연속적으로 나열되며, 마지막에는 '\0' (NULL)으로 끝나는 배열이다. 위 그림과 같이 문자열을 만드는 방법은 아래와 같다. char string[11] = "hello worl

ansan-survivor.tistory.com

 

(2차원 배열)

https://ansan-survivor.tistory.com/1263

 

[C언어] C언어 2차원 배열 선언 및 초기화

아래와 같이 2차원 배열 형태로 선언할 수 있다. 그렇다고 실제 메모리 주소값이 저렇게 생긴 것이다 아니다. 메모리 주소값은 아래와 같이 byte가 증가하며, 다음 배열은 그 뒤에 이어서 쭉 증가

ansan-survivor.tistory.com

반응형

*3차원 배열의 간단한 예시

#include <stdio.h>

int main()
{
	// 변수[depth][row][column] 구조이다.

	int arr1[3][3][2] = {
		{
			{1, 2},
			{3, 4},
			{5, 6}
		},
		{
			{7, 8},
			{9, 10},
			{11, 12}
		},
		{
			{13, 14},
			{15, 16},
			{17, 18}
		}
	};


	return 0;
}

출력은 2차원이나 똑같다 다만 depth 항목이 추가될 뿐이다.

 

 

반응형
반응형

 

아래와 같이 2차원 배열 형태로 선언할 수 있다.

그렇다고 실제 메모리 주소값이 저렇게 생긴 것이다 아니다.

메모리 주소값은 아래와 같이 byte가 증가하며, 다음 배열은 그 뒤에 이어서 쭉 증가한다. 실제 구조는 1차원적으로 생겼지만, 컴파일러를 통해 OS에서 이를 마치 2차원으로 간주하여 연산을 가능하도록 도와주는 것이다.

2차원 배열을 선언하고 출력하는 방법.

#include <stdio.h>

/*
	2차원배열 초기화 입력되지 않은 곳에는 자동 0 할당
*/

int main()
{
	// 2차원 배열의 초기화방법.
	// 가로길이에 대한 정보는 반드시 제공해야한다. (세로길이는 없어도 됨)
	// 그러면 나머지 길이는 컴파일러가 계산해서 넣음.
	int arr1[3][3] = {
		{1, 2, 3},
		{2, 3, 4},
		{4, 5, 6}
	};
	/*
	아래와 같은 형태의 행렬이 만들어짐
	[1, 2, 3]
	[2, 3, 4]
	[4, 5, 6]
	*/


	int arr2[][3] = {
		{1},
		{2, 3},
		{4, 5, 6}
	};
	/*
	아래와 같은 형태의 행렬이 만들어짐, 없는 곳은 0으로 채워짐
	[1, 0, 0]
	[2, 3, 0]
	[4, 5, 6]
	*/

	// 호출할때 함수변수는 arr[row][column] 이다.
	printf("행렬값 호출하기 arr1 2행 2열 : %d\n", arr1[1][1]);
	printf("행렬값 호출하기 arr2 3행 1열 : %d\n", arr2[2][0]);


	return 0;
}

(결과)

반응형

 

(아래는 2차원 배열의 사이즈를 보는 방법)

https://ansan-survivor.tistory.com/902

 

[C언어] 2차원 배열의 크기 보기 배열의 sizeof 사용법

배열의 크기를 보는 방법에 대한 예시 sizeof 로 크기를 확인하는데, 확인 방법과 해석은 아래와 같다. #include /* 2차원 배열의 크기 sizeof에 대해서. */ int main() { // 2차원 배열의 sizeof 크기 구해보기.

ansan-survivor.tistory.com

 

반응형
123

+ Recent posts