#include <stdio.h> typedef struct abcd { int name; struct abcd* next; } Node; // int main() { Node* head; Node* tail; Node* temp; Node* post; Node* pre; // 초기상황 head = (Node*)malloc(sizeof(Node)); tail = head; head->name = 0; head->next = NULL; // 10 이 생기고 붙음 temp = (Node*)malloc(sizeof(Node)); temp->name = 10; temp->next = NULL; tail->next = temp; tail = temp; // tail->next 도 가능 ( 같은 얘기 ) // 20 이 생기고 붙음 temp = (Node*)malloc(sizeof(Node)); temp->name = 20; temp->next = NULL; tail->next = temp; tail = temp; // 10 20 출력 for( temp = head->next ; temp != NULL ; temp = temp->next ) { printf("%d\n", temp->name ); } // 앞에서 부터 차례로 삭제하고 초기상황으로 돌림 post = head; pre = head->next; while( pre != NULL ) { post = pre; pre = pre->next; free( post ); } tail = head; free( head ); return 0;
typedef : 사용자가 정한 자료형 ( struct abcd 를 Node 로 줄여서 쓰는 효과 )
모든 포인터 변수에는 NULL 이 대입가능. '아무것도 가리키지 않는다'
1) (Node*)malloc(sizeof(Node)) 생성
2) temp = (Node*)malloc(sizeof(Node)); temp가 가리키게 한다.
temp->name = 10;
temp->next = NULL;
값 대입
4) tail->next = temp;
tail = temp; // tail = tail->next 도 가능
앞 노드와 뒷노드를 연결시켜주고 tail이 마지막 노드를 가리키게 한다.
post = head;
pre = head->next;
while( pre != NULL ) {
post = pre;
pre = pre->next;
free( post );
}
tail = head;
free( head );
#include <stdio.h> int add( int i, int j ) { return 100; } // int main() { int (*fp)( int, int ); // 함수포인터 fp = add; // fp 라는 포인터는 add 라는 함수를 가리킨다. printf("%d\n", fp( 10,20 ) ); // fp 가 가리키는 함수가 호출된다. return 0; }
int (*fp)( int, int )
매개변수가 int, int 이고 리턴타입이 int 인 함수를 가리킬 수 있다.
#include <stdio.h> typedef struct temp { int data; int (*add)( int ); }Temp; // int Temp_add( int i ) { return 10 * i; }; // 메모리 할당 + 함수연결 + 변수 초기값 부여 Temp* new_Temp() { Temp* tmp; tmp = (Temp*)malloc(sizeof(Temp)); tmp->add = Temp_add; tmp->data = 100; return tmp; } // int main() { Temp* t; t = new_Temp(); // t->data = t->add( 10 ); printf("%d\n", t->data ); free( t ); return 0; }
구조체 안에 함수는 선언 불가능하지만 함수포인터는 가능하다.
Temp* t; - 이것은 포인터, 구조체의 실체를 가리키는데, 그 안의 변수는 new_Temp() 함수의 tmp 가 가리키는 공간을 가리키게 되어 값이 대입된다.
#include <stdio.h> int main() { int i; int* t; float j; void* vp; // i = 100; vp = &i; t = (int*)vp; printf("%d\n", *t ); // *((int*)vp) // j = 3.14; vp = &j; printf("%f\n", *((float*)vp) ); return 0; }
int* 는 int 형 기억공간을 가리킬 수 있었다.
void* 는 모든 기억장소를 가리킬 수 있는 포인터다.
( 정수형 실수형 구조체 공용체 등 )
단, 해당 기억공간 안에 저장된 내용에 접근할때는 해당 타입으로 캐스팅
해주어야 한다.
#include <stdio.h> typedef struct temp{ int data; int (*add)(void*, int); }Temp; // int Temp_add(void* self, int i){ Temp* this; this = (Temp*)self; return i * 10 + this->data ; } // Temp* new_Temp() { Temp* tmp; tmp = (Temp*)malloc(sizeof(Temp)); tmp->add = Temp_add; tmp->data = 100; return tmp; } // int main(){ Temp* t; t = new_Temp(); // t = tmp; // t->data = t->add( t , 20); printf("%d\n", t->data ); free( t ); return 0; }
구조체 안에 선언된 모든 함수의 첫번째 매개변수 형태는 void* 로 한다. 구조체 안의 함수포인터로 호출하는 모든 함수는
Temp* this;
this = (Temp*)self;
이 코드를 맨 위부분에 써주도록 한다.
이러면 실제 함수 호출시에
t->add( t, 20 );
t 자기 자신을 매개변수의 첫번째에 넣어주게 된다.
add 입장에서는 자신이 속하여 있는 메모리 공간을 this 가 가리키고 있다. 즉 this 포인터는 자기 자신이 속해있는 구조체를 가리키게 되고, 구조체 안의 변수와 함수에 접근 가능해진다.
#include <stdio.h> typedef struct temp { int data; int (*add)( void*, int ); }Temp; // int Temp_add( void* self, int i ) { Temp* this; this = (Temp*)self; return i * 10 + this->data; } // Constructor 의 역할은 변수의 초기화!! void Temp_Constructor( void* self, int i ) { Temp* this; this = (Temp*)self; this->data = i; } // Temp* new_Temp( int d ) { Temp* tmp; tmp = (Temp*)malloc(sizeof(Temp)); tmp->add = Temp_add; Temp_Constructor( tmp, d ); return tmp; } // int main() { Temp* t; t = new_Temp( 0 ); // t->Temp_Constructor( .... ); // t 라는 포인터를 통해서 호출 불가능 t->data = t->add( t, 20 ); printf("%d\n", t->data ); free( t ); return 0; }
Temp_Constructor 는 new_Temp 호출할때 호출된다.
주 용도는 구조체 안의 함수포인터 아닌 변수들의 초기값을 준다.
이것은 포인터를 통해서 호출할 수 없는 함수다.
즉 t->Temp_Constructor( .... ); 이런 식으로 접근은 안된다.
#include <stdio.h> void add( int i, int j ) { // return; } // int main() { add( 10, 20 ); return 0; }
리턴타입이 void 로 선언된 함수를 서브루틴
이라고 한다.
class Sample { int i = 0; int add( int i, int j ) { return 100; } } // public class Test061 { public static void main( String[] args ) { System.out.println("HelloWorld"); } }
class 는 실은 구조체??
class Temp { int data = 100; int add( int i ) { return i * 10; } } // public class Test062 { public static void main( String[] args ) { Temp t = new Temp(); t.data = t.add( 20 ); System.out.println( t.data ); } }
참고로 클래스 이름은 대문자로 시작한다.
new Temp(); 을 먼저 만들어 주어야 한다 : 인스턴스(instance)
라고 부른다.
Temp t = ... , 클래스 이름으로 변수를 선언한다( 참조형변수
). 인스턴스를 대입한다.
앞서서 선언한 변수 ( 참조형변수
또는 reference
라고 부른다 ) 를 통해 클래스에서 선언된 변수명으로 접근이 가능하다.
참조형 변수를 통해 클래스에서 선언된 함수를 호출할 수 있다.
// 위에서 C로 구현한 코드를 java로 옮기는 꼴 class Temp { int data = 100; int add( int i ) { return i * 10 + this.data; } } // public class Test067 { public static void main( String[] args ) { Temp t = new Temp(); t.data = t.add( 20 ); System.out.println( t.data ); } }
t.add( 20 ); 이것과 같이 호출했을때, 함수 안에서 this 라는 포인터를 쓸 수 있다.
java 의 모든 클래스 안에서 선언된 함수는 내부에서 this 를 쓸 수 있고 , 이것이 가리키는 대상은 호출시에 사용했던 포인터가 가리키는 대상 , 즉 함수가 소속된 인스턴스를 가리키게 된다.
this 를 통해서 data 와 add 함수에 접근할 수 있다.
this 가 가리키는 대상은 어느 참조형 변수를 통해서 호출하느냐에 따라 틀려지게 되고, 이를 통해서 같은 함수의 실체를 호출하더라도 각각 다른 결과를 만들어 낸다.
class Temp { Temp( int i ) { this.data = i; } int data = 100; int add( int i ) { return this.data + i; } } // public class Test070 { public static void main( String[] args ) { Temp t = new Temp( 0 ); t.data = t.add( 20 ); System.out.println( t.data ); } }
리턴타입 없고 클래스 이름과 같은 함수를 Constuctor ( 생성자함수)
라고 한다. 주 역할은 클래스 안에서 선언된 변수의 초기화이고, t.Temp(); 와 같은 형태로 포인터로 호출할 수 없다.
생성자 함수는 참조형 변수 선언시에는 호출되지 않고, 인스턴스가 생성되는 시점에 호출된다.
클래스 안에서 변수를 선언할 수 있고, 함수를 선언할 수 있다.
클래스 안에서 선언된 변수 : 멤버변수
, 프러퍼티 ( property )
클래스 안에서 선언된 함수 : 멤버함수
, 메서드 ( method )
생성자 안에서는 this
라는 포인터를 사용할 수 있고, 이것을 이용해 주로 멤버변수를 초기화 한다.