포인터를 어떻게 이해하셨나요?

geekforum의 이미지

C언어를 공부하고 있는데 포인터 때문에 번번히 막히는군요. 책을 볼때는 알것 같은데 막상 이걸 어떻게 써야 할지, 왜 포인터라는게 있는 것인지 막연하네요. 예제는 그냥그냥 풀수 있고 뭔가 알것 같기는 한데 확실히 손에 잡히지는 않는 그런 상태입니다. 그냥 포인터 변수만 나오면 괜찮은데 함수 포인터다, 구조체 포인터다...갈수록 복잡해지더군요.

여러분들은 포인터를 어떻게 이해하셨는지요? 책을 보면 각자 비슷비슷하게 설명은 하고 있지만 제대로 이해가 되지는 않습니다. 포인터를 어떻게 이해하면 좋을지, 포인터를 언제/어떻게 사용해야 할지 여러분이 가지고 계신 노하우를 좀 전수해 주시면 안될까요?

댓글

익명 사용자의 이미지

1

익명 사용자의 이미지

전 포인터를 이해했어요.. 완벽하게 하하하ㅏㅎ
쉬워여.. **(a*)[3][3]
이게 멀까여?

익명 사용자의 이미지

포인터를 어찌 설명하랴..

쓰는 방법을 익히는 것이지..

많은 예제를 통해 익히면 되느니..

다시 한번 말 하지만..

나름대로 정리 해 둘 필요가 있다..

틀리는 정리라 할 지라도..

그렇다..

익명 사용자의 이미지

[포인터를 이해할 수 있는 정도!]

프로그램을 좀 크게 만들다 보면 이런 생각이
듭니다. 분명히.

"아, 젠장..열라느리군,"
"아, 젠장..이렇게 말고 다른 방법 없어?"
"아, 젠장..이문제를 어떻게 해결하지?"
"아, 젠장..어떻게 해야해.."

그중에 80%에서 포인터를 사용할 것입니다.
그럼 그때 C언어의 포인터 부분을 다시 보세요.

그리고 포인터는 아래글(다보지 않았찌만)
처럼 매우 다양하고 어렵게 표현될수 있습니다.

하지만 쫄지 마세요.
어려운 포인터를 써야 할때가 왔다는것은 님이
그만큼 크 프로젝트를 수행하고 있는 뜻이
될수도 있으니까요.

익명 사용자의 이미지

문자열 몇번만 다뤄보면 후딱 이해될것인디..

winchild의 이미지

포인터를 이해하실려면...

최소한 자료구조를 탐하셔야 합니다. 그냥 이해하는것이 아니라 내마음으로 이해하여야 한다고 말씀을 드리고 싶군요.

아래에 참으로 많은 분들이 포인터를 설명해 주실려고 애를 쓰셨지만 제대로 설명하려면 책한권으로 써도 부족합니다.

설명하는 사람이 더 어려운 단어를 써버리는 오류에 빠지게 되어 버리거든요.

최소한... 자료구조하나는 이해하실려고 노력하시기를 (책한권 떼야 함다) 그러면 어느순간 포인터를 이해하시고 계실것 입니다.

이상 도움되지 않는 조언이었습니다.

- 겨울아찌 -

- 겨울아찌 -
winchild@gmail.com

익명 사용자의 이미지

NAME
signal - ANSI C signal handling

SYNOPSIS
#include

void (*signal(int signum, void (*sighandler)(int)))(int);

이걸 보면 알수 있죠...포인터가 무엇인지..

byukbyng의 이미지

포인터는 필요에 의해서 생겨난 것이고,

C언어가 장수 할수 있는 근거라고 생각하는

사람입니다....

제가 생각하기에.. 앞으로 책을 볼경우에...

int, char, long, float 의 type만 있는것이아니라..

C에는 int*, char*, long*, float* 도 있다고 생각하고,,, Cascade되어질수 있다는 전제만

생각하고,(물론,이론적인 이해도 필요합니다.) ,,, 이용해보면,, 증말 편하다는 느낌을
얻게 될거구,,, 어느 순간에는 포인터 없이는
프로그램을 짤수 없다는 생각이 들던데요....

익명 사용자의 이미지

typedef struct {
int a;
int b;
} struct_xxx;

void dddd()
{
struct_xxx tmpa;
struct_xxx *data = &tmpa;

data->a = 0;
data->b = 1;

}

이거 재미있네...하하

diziso의 이미지

다른 책과는 조금 다른 설명을 읽었던 기억에 몇자 적습니다.^^; 객체지향에 관해 설명하기 위한 서두(?) 였던걸로 기억하는데염.

'자료형은 연산자가 따라다닌다.'
ex)int 형은 4바이트(^^;) 의 저장공간을가지며
사칙연산(+-*/),논리연산,비교연산 등등등 다양한 연산자가 따라다닌다는 소리...

즉 사실상 C 에서 써온 여러 변수들은 하나의
객체를 생성해 썼던것이며 다만 원하는 객체
를 만들어 쓰지 못했던것..

여기에 클래스라 부르는것이 추가 되어 이제
원하는 객체를 만들어 쓸수 있게 됬다....(생략)

잠시 객체지향은 접어 두고 포인터루 돌아와서.
원하는 바는 메모리의 주소를 이용한 데이터
접근(읽어오구 바꾸고) 를 하고 싶은것이고..
이를 위해 포인터 라는 데이터 형을 만들어 두었다는 것...
포인터 형은 4바이트의 메모리공간을 확보한뒤
주소를 기억하구여 따라오는 연산자로 중요한건
1.그 메모리 주소값을 알고자 할때 = 아무연산자도 않쓰고 그냥 포인터 변수 이름만쓰면 됨
2.그메모리에 있는 내용을 알고 싶을때 =
포인터변수 이름앞에 * 를 붙임으로서 표시.
3.메모리 주소의 증가와 감소 = ++,-- 연산자를
이용하되 증가되는값은 1바이트가 아닌
해당 자료형의 크기만큼씩 증가,감소.

2번 내용을알고자 할때 중요한건 해당 메모리
번지에 어떤 형태의 자료가 들어 잇는지 알아야
내용을 알수 있져..(이억이야 모두2진수로 기억하고 그게 무슨의미인지는 해당 자료형이 말해주므로) 그래서 그걸 명시하기위해
포인터 변수 선언시 int*,char* 이런식으로
명시하기도 하며.. 변수 이름앞에
(int*)변수이름 이런 식으로 형변환을
하여 쓰기도 한다는....

머 사실 이해한때는 포인터 변수는 메모리 주소
를 다루는 변수 라고말할수 밖에 없던 시절
감은 잡고 쓰다 가.. 이소리 저소리 듣다보니
어떤 식으로 설명하는것이 더 좋을까 생각해볼
여유도 생긴거져...

즉 포인터 변수는 메모리 주소를 기억하는
변수이고.. 메모리 주소를 관리함에 적합한
연산자가 따라 다닌다는..

일단 이걸 이해 하면 2중포인터니 함수 포인터니 다 아는 이야기가 될것이라생각됨니당..
구조체에 접근하기 위한 연산자(?) 함수가 메모리에 로드된 주소를 알면 해당 함수를 불러쓸수
있는데 이때 는 무슨 연산자(?여기선 어감이
좀 별루인데..훔.. 방법정도가 더좋을지도)
를 쓰는지느.. 책보구 익히구 쓰다보면 기억두되구..^^;

왜 포인터가 있는지는.. ^^; 글쎄여...
편하단 이유로 원하는 사람이 많아서가 아닐지
사실 왜 있다기 보단 원하는사람이 많아서
없에지 않은거겟져.. ㅎㅎ 원래는 데이터의
저장이나 함수 등을 사용하기 위해 로드된
메모리의 시작번지를 사용함이 당연했으니..

다만 그게 머리아픈 사람을 위해 데이터등에
이름 붙여 쓰기 써비스를 제공하게 됐긴해도
그건 꼭 이름을 붙여야만 하며 이름을 모르면
않된다는 제약이 생기다 보니 ㅡ.ㅡ;
기존의 메모리의 시작번지를 이용한 접근도
가능하도록 해둔것이 아닐런지...

거대한 데이터를 복사해서 넘겨줄것인가
시작번지만 넘겨줄것인가..
다른모듈(OS,라이브러리,팀원이만들엇거나등등)에게 적당한 조건이 되면 어떤함수를 불러
달라 부탁할때 함수를 만들고 시작번지를
넘겨주지 않으면 도데체 어떤방법을 쓸것인가.

등등을 생각해 보면 왜 필요하다기 보단..
없을때 어떤식으로해야 그공백을 매꿀것인가가
문제겠져..^^

(% 포인터변수와 인트형의 크기는 시스템에
따라 틀리다고 알고 잇습니다만은.. 여기선
크게 중요한게 아니라 그냥 제컴에맞춰서^^;;)

익명 사용자의 이미지

저는 초등학교때부터 C/C++를 사용하기 시작하였고 지금도 계속 C/C++를 사용하고 있습니다.

초반에는 포인터를 제대로 이해하지 못하였습니다. 고등학교를 지나 대학교에서 포인터에 대한 개념이 자연히 생기더군요.

지금은 포인터도 하나의 변수처럼 사용하고 있고 포인터로 발생되는 프로그램상의 문제는 거의 없습니다.

포인터는 단지 주소를 값으로 가지는 변수라고 이해하면 가장 빠르더라고요.

익명 사용자의 이미지

포인터요..
저두 첨에는 님과 같았습니다.
근데여..
포인터는 원리를 알면 쉬워요..
기본에 충실하면...
구초체,함수 포인터 모두 똑같은 개념이거든요..
포인터는 단지..
주소를 저장하는 변수라고 생각 하시면 돼요..

그리고 일반 변수 처럼 쓰시면 됍니다.

단지 중요한건 포인터는 지역 변수 처럼
없어 지질 안구 그대로 남아 있다는 거죠..
모 call by address 프로그램 함 분석 해
보시면 알겁니다.

도움이 돼셨는지 모르겠네여..

익명 사용자의 이미지

야한 잡지를 보고 이해했습니다 ㅡ_ㅡ;;
근데 왜 이런걸 물으시죠?

익명 사용자의 이미지

간단히 말씀해서 포인터변수는
다른변수의 주소값을 저장하기위해서
사용됩니다.

그리고 그주소값을 호출해주면
변수를 다른함수등에서도 제어해줄수있죠

모기의 이미지

포인터를 정확히 이해하실려면 컴퓨터구조, 또는 마이크로프로세서를
공부하시면 확실히 왜 필요한지 알게 됩니다.

CPU의 기계어(인스트럭션)에 보면, 상대 주소(relative addressing) 이나
간접주소(indirect addressing) 지정방식이 있습니다.

addressing이라는 것은 어떤 데이터가 들어 있는 위치라고 이해하시면
되고 특정 어드레스가 지정하는 메모리를 변수로
이해하시면 됩니다.

그런데 상대 어드레싱이라는 것은 특정한 메모리 위치로 부터 +- 몇칸
떨어져 있는 메모리 위치를 지정해서 그 위치의 값을 읽어오거나
그 위치에 값을 써 넣을 때 사용하는 것이고 간접어드레싱은
지정된 메모리 위치에 들어 있는 값을 다시 주소 값으로 사용해서 그 위치의
값을 읽어오거나 또는 그 위치에 써 넣는 것입니다.
바로 상대 어드레싱은 배열이나 단순 포인터 연산을 한 인스트럭션으로
표현할 수가 있고, 간접 어드레싱은 포인터변수를 직접 인스트럭션으로
바꿀 수가 있는 겁니다.

어셈블리나 기계어로 직접 프로그래밍 하는것과 유사한 효과를
포인터 변수를 통해서 지정할 수가 있죠.
함수의 포인터는 프로그램의 흐름을 바꾸는 jmp 같은 인스트럭션에
간접어드레싱이나 상대 어드레싱을 사용하는 것입니다. 상황에 따라
여러개의 서브루틴중에서 하나를 골라서 갈 수 있게 할 수 있겠죠.

즉, C언어의 태생 자체가 고급언어 이면서 하드웨어 제어등,
저급언어의 기능을 갖도록 할 목적이 있었기 때문에 C언어 문법 자체에
하드웨어 인스트럭션을 직접 쓰는것과 유사한 효과를 얻을 수 있도록
해주는 것이 포인터입니다.

익명 사용자의 이미지

가장 정확한 답이라고 생각합니다...
역시 ...

익명 사용자의 이미지

이곳에 질문해서 죄송합니다..

아래 구문이 뭔뜻인지 도저히 모르겠습니다...

커널의 list.h에 있는 건데요...

#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

포인터...엇갈리네요..ㅠㅠ

익명 사용자의 이미지

황당한 표현식 같아서 돌려보구 이해가 되더군요. ^^

어떤 Type 의 Point 변수 의 member 의 Address 를 그 Type의 Address 로 얻는겁니당.

말이 넘 어렵죠? ^^

근데 여기서 헛갈리는부분은 unsigned long)(&((type *)0)->member))) 의 0 값이겠죠?

이건 Running 싯점의 현재 ptr 위치를 얻기위해서 하는겁니다.
즉 위 ptr 의 base 를 coding 상에서 잡기위해서 그런거죠.

아무래두 돌 날라올것 같네여....
ㄴ(-_ㅡ)ㄱ=3=3=3

익명 사용자의 이미지

아 그렇군요...! 답변 감사합니다. ^^

사족 같지만 제가 이해한방법으로 조금 설명을 추가할께요..

풀어서 쓰면 다음과 같습니다....

#define list_entry(ptr, type, member) \
(
(type *) // 리턴형을 지정할뿐 별의미 없고요.
(
(char *)(ptr)- //이건 ptr의 포인터 주소입니다.
//다음 라인이 핵심인데요.. 이게 바로 member변수의 offset!
(unsigned long)(&((type *)0)->member)
)
)

즉, 현재 ptr의 주소에서 member변수의 오프셋을 뺐으니까
당연히 type형이 리턴되는거죠!

참고 테스트 코드...

#include
struct inode {

unsigned long i_ino;
unsigned long i_blksize;
unsigned long i_blocks;
unsigned long i_version;
unsigned long i_nrpages;
};

int main()
{
printf("%d\n", (unsigned long)( &((struct inode *)0)->i_ino)) ;
printf("%d\n", (unsigned long)( &((struct inode *)0)->i_blksize)) ;
printf("%d\n", (unsigned long)( &((struct inode *)0)->i_blocks)) ;
printf("%d\n", (unsigned long)( &((struct inode *)0)->i_version)) ;
printf("%d\n", (unsigned long)( &((struct inode *)0)->i_nrpages)) ;

return 0;
}

씨가 참 아름답군요 :)

익명 사용자의 이미지

왜 빼죠?

더해야 하는것 아닌가요??

흠... list.h 는 구조체 리스트에 쓰이는거라서 그런것 같은데...

에휴 모르겠다..누가 답좀 해봐요

익명 사용자의 이미지

참고로... type은 당연히 member를 가질수 있는 struct나 union이어야 합니다...

list.h가 어디에 쓰이는지 확인지 먼저 필요할것 같군요...

익명 사용자의 이미지

이거 컴파일해보니까 다음과 같은 에러가 나오던데요?
어떻게 해야 되는 건가요?

printf가 들어간 문장에서....

ttt.c: In function `main':
ttt.c:11: invalid lvalue in unary `&'
ttt.c:12: invalid lvalue in unary `&'
ttt.c:13: invalid lvalue in unary `&'
ttt.c:14: invalid lvalue in unary `&'
ttt.c:15: invalid lvalue in unary `&'

익명 사용자의 이미지

글쎄요.
전 gcc로 했는데요..
딴 컴파일러는 잘 모르겠네요..

익명 사용자의 이미지

저도 gcc로 했는뎅..(-.-;)

딴분들은 다 잘 되나요?

익명 사용자의 이미지

gcc 로 테스트 해 봤는데...잘 됩니다.

결과는...
0
4
8
12
16

이 찍히는군요...;;

gcc 2.96 입니다.;

익명 사용자의 이미지

임성훈님이 쓰신글에 오타가 있어서 글을 올립니다.
int a[99]는 100개가 아니라 99개이므로 int a[100]가 맞을꺼 같네요

익명 사용자의 이미지

a[99][99] 는 10000개가 아닙니다..
a[99]는 0~98까지 배열은 정의되는거죠

그러니 99X99개입니다..

사소한것에.. 착각을 하고계신듯합니다

imavatar의 이미지

이첫머리 글다쓰고 추가했숨니당... 앞뒤를 연결하기위해 이젠자야징.ㅠ.ㅠ
c언어의 대다수 변수 ...각종 일반변수 다차원 배열의 구조체 공용체 링크드 리스트가 강력한 이유!! 그리고 특히 구조체 공용체 링크드 리스트가 재대로 써먹을수 있는 이유 바로 막강한 포인터의 메모리 주소의 순간이동을 할수 있는 기능에 있숨니당...

이제부터 오리지널 처음 글이였던 헛소리가 시작됨니당..
int a[99]하면 0-99 까지 100개의 숫자 배열이 선언되죵?
그냥 100개 선언해 버리거나 for 100개 변수 만들면 되는데 저짓 왜 할까여~
노가다 방지와 실용적이 히해할때 명확하기 때문이라고 생각함당-_-;;;
혹이 이런 배열 보셨어영?
a [99][99]
다차원 배열이죠... 0~99 까지의 숫자배열을 0~99개만큼 선언한다
저말은 앞에 0~99는 뒤에 0~99의 간판정도되는 것이고-_-
뒤에 0~99 짜리 합해서 10000개의 배열만이 데이타를 저장할수 있는 변수라고 할수있겠죵? 그쵸??
운동하고 잘라고 폼잡다가 쓰는 글이라 정신이 가물가물하고 아마 담날 아침에보면 오타나 잘못된부분이 많을듯 흐미 지송-_-;
암튼 그럼왜! 머리아프게!!!!!!
a[9999]하면될걸가지고 머리아프게!! a[99][99]이짓거리는 왜 하냐고요!!
위에서 말했듯히 배열에 자료 입력할때 노다가 방지 편의성 이해성때문이라고 졸린머리가 답하고 있숨니당..음...맞나요^^;;;;;;;
위에서 앞에 99배열은 실제 데이타가 저장되는 공간이 아닌 해당 99배열을 가르키는 광고 간판또는 전화번호라고 헀고 뒤에 99에서야 해당광고 간판의 내용물 즉 실제 숫자데이타가 들어가는 곳이라고 할수 있겠다고 지가 아까 말했나여 가물가물-,.ㅡ
어이 회집 간판을 보고들어가면 가계 안에 불고기의 반대 물고기가 회뜰? 차례를 기다리구 있잔수-_-;
근디 회집모여 있는 지역이면 간판없이 물고기 수보고 다음 가계 판단한다면 얼마나 골치 아프겠수-_-;;
잘하는집 기억할라면 회먹구 물고기 수 세구있어야 겠잔수-_- 않그러우 아찌!!!!!

이제 또 화제를 잽싸게 바꾸어서 그럼 포인트 거시기는 모시냐!!!
그냥 a선언하면 a데이타 저장소 &a데이타 저장되는 간판(메모리주소)
근디 포인트 편수 *a선언하면 a데이타 저장소 &a데이타 저장되는 간판(메모리주소)

이것도 노가다 방지를 위해ㅡ.ㅡ;;; 간판꺼낼때 &칠필요 없으니 포인트 변수를 선언한다고라고라 하면 헛소리일듯 하고!!
암튼 포인트는 여기서 끝!! 기분이당!!

이제 삼천포로 빠져서 다차원 배열!!
a[99][99]를 포인터로 펴현할수 있다 이검니당!!
정확히 말하면 저거의..
a[0][0]일듯 함 그쵸?
그 거기기를 어떻게 한다 하면은
**a하면 땡임당!
a[0][0]=7;
**a=7;이랑 같다 이검니당!!..

&a[0] 이넘의 간판은 a랑 같은 말임니당..
횟집종합상가 입구(포인터로는 a)에있는 간판을 보고 들어가서 사시미횟집이란간판을 찾으면
그사시미 횟집 안에 수백마리의 우굴거리는 나의 사랑랑스럽고 백수생활에 그리운 먹거리 물고기들이 있숩니당!!
그런 사시미횟집을 가르키는게 a[0]임당!
포인터로는 *a임당...
이제 내가 가장 좋아하는 그머더라 잠만 에잇 물고기 이름 생각 않나넹..암튼 이런사연으로 횟집 1호물고기 쭈구미가 배열0순위로 발탁!!
a[0][0] 빠빠밤~ 횟집종합상가에 있는 사시미 횟집에 있는 어항에 가장먼저 눈에 뛴 쭈구미씨를 소개함당!!
포인터로 따지만 **a
그리하여 **a되었다는 기가막힌 사연히-_-

정리하자면
a안에 있는 것은==1(*a의 간판 이름)--1번지로->*a안에 있는 것은?=20(**a의 간판 이름)--20번지로->**a안에 있는 것은==쭈꾸미!!
뒤에 간판이름이라 말할려고 한사람 나서지 마쇼!
쭈꾸미는 음식이지 횟집의 간판이 아니란 말요!!.

a[99][99][99][99][99][99][99][99][99][99]
이런 무식하게 디따 큰 배열이 있다 하더라도
포인터로는 위와 같은 기가막힌 사연에 의해!
**********a이 되어 버린다는 검당!!

아직도 주소는 포인터 변수 아니라도 선언되기 땜시! 포인터 변수가 필요 없다고요! 포인터 변수는 주소만 보여주는 용도 뿐만 아니라 직접 그주소로 순간이동해버리는 기막힌 아이템임당! 주소가 수백 수천개라도
아주 충실 그리고 무식하게 순간이동을 함니당..
대단다죠 그춍..

c언어의 대다수 변수 ...각종 일반변수 다차원 배열의 구조체 공용체 링크드 리스트가 강력한 이유!! 그리고 특히 구조체 공용체 링크드 리스트가 재대로 써먹을수 있는 이유 바로 막강한 포인터의 메모리 주소의 순간이동을 할수 있는 기능에 있숨니당...

옆집에 사사미?라는 횟집이 새로 생겼는데 장사를 허벌라게 잘해서 옆집 닥박에 부도처리해서 사시미회집을 홀라당 망하게 해버렸숨니당...
이제 옆집망해서 다른 횟집들어와서 경쟁 상대가 생길 우려가 있기에 아주 싼값에 옆집을 사들였숩니당...

근디 물고기수를 늘리면 옆집처럼 망할꺼 같해서
가계크기랑 물고기수는 고정시켰슴니당...
근디 이넘들이 하도 장사를 잘해서 옆집을 닥박에 망하게 했기때문에 옆집 망한지도 몰르고 옆집단골이 옆집 문을 퍽퍽 뚜드림니당 문열라고-_-;;;
그래서 잔머리의 천재인 이주인이 옆집 단골고객을 유치 전략에 의거하여
옆집간판은 고대로 달구선
옆집 문열고 들어오면 바로 자기집에 들오게 벽뚫어버리고 같은 가계인거 처럼 위장시켜서 문을 만들어 버렸슴니당..

그래서 우리의 아이큐가 붕어 아이큐라 3인 사시미 단골고객은 사사미가계인줄도 모르고 회먹를 꿀꺽 꿀꺽 먹습니당 더 맛있어졌다고 눈치도없이 조아합니당-_-;;;

그런 엽기정인 상황을 포인터에서는
*a
*b
b=a
b=꼴뚜기
라는 말로 표현할수 있습니다..
정리하면 *a *b는 같은 변수가 들어가는 것뿐 만 아니라 같은 변수의 간판으로 무뉘만 *a *b인 초사기성 변수가 되어 버림니당..

이런 초사기성 포인터 변수는 일반 변수말고도 구조체 공용체 링크드리스트에서도 허다하게 사기치면서 돌아다니는 간큰 변수가 바로 그유명한 포인터 변수
였을꺼입니당
아마 점점더 가물거리는 제 기억으로는-_- 맞을검니당..

리눅스 아니-_-;; c에서는 포인터라는 넘이 있기에
포인터와 같이 있을때는 세상에 두려운것이 없었다라는 전설이 있습니다..

점점더 복잡해지는 c언어 문법은 결국 포인터를 이리저리 응용해서 비빔밥비벼먹들이 이리저리 바꾼것 뿐이라고 저는 확신하기에는 넘 졸림군요-_-;;;

맘같해서는 구조체 시작해서 링크드 리스트 까지 이런 엽기짓을 해보고 싶지만 벌써 글쓰느라 40분이 지나고-_- 점점 오타랑 헛소리 심해지는 이상황..

평소에 맘속에 가지고 있었던 헛소리 한번 지껄이고 잠니당^^:;

여기서 자제를 하구
열분!! 맘먹이게 달려있슴니당..
책에 숫자나온다고 쫄지 마세영..
모두 편안한 잠자리 되세영.

익명 사용자의 이미지

니☆마☆ 펴주너를 씃에0. ㅋㅋㅋ

익명 사용자의 이미지

읽다가 문체에 지쳐 포기했슴다.. -.-

익명 사용자의 이미지

으.. 장문의 글 쓰시니라 너무 수고하셨습니다.
그렇지만 통신어체와 횟집 비교는 너무 해깔리네요.

조그만 친절히 써주셨으면...

익명 사용자의 이미지

글쓰셔 놓은게 좋은데..좀더
좋게 코롬 ..적어 주세요..^^

GunSmoke_의 이미지

장문의 글, 고맙습니다만 다음번에 글 올려주실때는 쉽게 이해할 수 있도록 부탁드립니다.

익명 사용자의 이미지

대학생이시면 프로그래밍언어론을 들으시고
그렇지 않더라도 프로그래밍언어론에 관련된
책을 보시면 지금 나온 포인터에 대한 모든 개념이 머리속에 잡힐겁니다 . - . -

아마그래머의 이미지

저도 C언어를 한지(군에 갔다온거 빼고) 1년반이 넘었습니다만. 이제야 좀 알겠다 싶을 정도입니다.
물론 아직도 시스템적으로는 우째 돌아가는지 잘 모릅니다만.. 너무 성급하게 생각하지 마시고 많은 예제를 접하시다 보면 자연스럽게 깨우치게 될껍니다.
^^;;

익명 사용자의 이미지

차라리 포인터 형을..

int *a,*b 이런거 대신..

pointer a,b 이런식으로 표시 하는게 나을꺼 같은데.. 헷갈리지도 않고...

익명 사용자의 이미지

그렇게 하면 더 헷갈리는데...

그렇게 쓰다가
나중에 * 이랑 ** 이랑 & 를 마구 섞어서 쓰다보면
정신 없어져요..
그때마다 pointer *a; 이렇게 쓰게 될 수도 있고.
계속 새로운 변수형을 만들기도 힘들죠.. ^^;;;

게다가.. 죽을 때까지 혼자서 개발 할 겁니까???
다른 사람들과 함께 하는 작업을 생각해야 합니다.

익명 사용자의 이미지

만들면 되죠.
typedef int* int_pointer;
이런 거는 프로그래머의 스타일 문제에 지나지 않습니다.

익명 사용자의 이미지

포인터가 꼭필요한 곳이 있습니다.
통신상에서 여러 패켓을 구분해 이에 맞는 동작을 하는 프로그램은 짜려고 할때죠.
예를 들면 100byte짜리 패켓이 넷트웍이나 serial통신 라인으로 들어 왔고 이데이터는 많은 패켓타입중하나인경우 이를 찾아야 한다면

C에서는 다음과같이 합니다.
struct pkt_hdr // packet header.
{
int pkt_type;
long pkt_len;
};

struct pkt_one
{
struct pkt_hdr hdr;
long other_data_one;
};
struct pkt_two
{
struct pkt_hdr hdr;
int other_data_two;
};
...

union pkts
{
struct pkt_hdr hdr;
struct pkt_one one;
struct pkt_two two;
....
};

위처럼 packet들이 정의 되있을때 다음과 같이 packet type을 구분하여 논리적으로 데이터를 처리할수 있다.

void proc_pkt ( byte *buf )
{
// pointer 의 위력.
struct pkts *pkts = (struct pkts *)buf;

switch (pkts->hdr.pkt_type ) {
case PKT_ONE :
if ( pkts->one.hdr.len == 100 ) {
do_something();
}
;break;
case PKT_TWO :
if ( pkts->two.hdr.len == 120 ) {
do_something();
}
;break;
....

};
}

위와같은 처리를 vbasic이나 java에서 할수 있을까요?
pointer없이 memcpy ()등 메모리 블럭 조작을 할수 있을까요?
java등에서는 메모리 조작을 일부러 막아 놓은것으로 알고 있습니다.
메모리 조작이 문제도 많이 일으키지만 위의 예처럼 통신 packet조작등에서 꼭필요로 하는 기능입니다.

별거 아닌것 같아도 없으면 무식한 방법을 써야 됩니다.

익명 사용자의 이미지

아래처럼 하는게 더 쉽지 않나요..?? 음..

아 성능이 아니라 음 짜는거 말이죠.. 자바의 메모리 접근 금지는
보안에 관한 자바의 신념.. 과 비슷한 겁니다.

그럼..

public class pkts {
do_something() { ..... }
}

public class pkt_one extends pkts {
long other_data_one;
}

public class pkt_one extends pkts {
int other_data_two;
}

// 어디선가의 함수..
public void proc_pkt ( pkts one ) {
one.do_something() ;
}

익명 사용자의 이미지

원래글의 의도는 버퍼에 얻게 된 데이터 byte배열을 구조적으로 파악하고자 할땐 어떻게 해야 하느냐 하는 문제 입니다.

버퍼에 데이터가 100개 들어와 있을 경우 이를 구조적으로 분석할수 있느냐죠.
C인 경우 type casting을 이용해 처리가 가능하다는 것이 원래 글의
의도 입니다.

// type casting.
union pkts *pkts = (union pkts *)buf;
pkts.hdr.pkt_type ...
pkts.hdr.pkt_len ...
pkts.one.other_data_two 등.
별거 아니죠. 하지만 다른 언어에선 이걸 지원안해줍니다.

답하신 글에서
-> // 어디선가의 함수..
-> public void proc_pkt ( pkts one ) {
-> one.do_something() ; ^^^^^^^^
-> }
라고 쓰셨는데 통신상에서 얻은 byte배열을 어떻게 pkts라는 클레스로
집어넣을까는 생각안해보신 것 같군요.

java는 아무거나 type casting이 되지 않죠.
java로
union pkts *pkts = (union pkts *)buf;
을 구현하려면 상당히 골치아픈 문제에 부닫힙니다.
C로는 한줄이면 될걸 java는 여러 클래스를 가져다 써야 할걸요.

음...

다른 좋은 생각 있으시면 굴비달아 주세요.

익명 사용자의 이미지

아.. 원문의 의도를 알았습니다.
음.. 언어의 원하는 바가 달라서 뭐라 말하기는 힘들군요..
음..

물론 자바는 그런 형태의 casting 은 지원 못 하죠..
뭐 굳이 그렇게 해야만 한다면.. 음..
이렇게 되겠죠.. 뭐..

// 어디선가의 함수..
public void proc_pkt ( byte[] buf ) {
one = getPkts(buf) ;
one.do_something() ;
}

// 어딘가에서 또..
public static pkts getPkts(byte[] buf) {
// 여기서 buf 를 분석해서 pkts 의 서브클래스를 돌려준다.
.....
}

어느것이 좋은가는.. 음.. 말하기 힘들군요.. 하지만.. 개인적으로는
골치가 아픈지언정 자바의 방식을 택하겠습니다.

님께서 해 주신 그 방법은 정말 포인터가 없으면 불가능한 방법이지만..
그런 방식은 정말 피하고 싶군요..

쩝..

그럼,

익명 사용자의 이미지

good job!!!

역시 코드가 깔끔하죠.

-영희-

익명 사용자의 이미지

위에서
// pointer 의 위력.
struct pkts *pkts = (struct pkts *)buf;
이아니라
// pointer 의 위력.
union pkts *pkts = (union pkts *)buf;

입니다.

익명 사용자의 이미지

저 그런데요..
-> 이것도 포인터 인가요?
설명좀 부탁 드립니다..^^:

익명 사용자의 이미지

asdf : 어떤 구조체를 가리키고 있는 포인터

(*asdf).var
=> asdf->var

보기 좋죠?

익명 사용자의 이미지

비유를 들어 설명하면...
포인터는 리모트 콘트롤러와 비슷한 것이지요.
리모트 컨트롤러가 없으면 직접 가서 채널을 바꿔야하지만 컨트롤러가 있다면야 어디서든지 간단하게 티비를 제어할 수 있습니다.
즉, 포인터는 변수를 원격조정(?)하는데 필요한 것이라 보심 됩니다.
구체적으로 말하면 어떤 변수에 접근하기 용이하지 않은 상황에서 그 변수에 접근할 필요가 있을때 포인터를 이용하지요.
(그 밖에도 웹에서 말하는 일종의 링크기능 같이 변수들을 링크(?)시켜 자동으로 값이 변하게 하는데 이용할 수도 있지만..설명하면 더 헷갈릴듯...)
무엇보다도 포인터가 왜 필요한지를 이해하고 느끼는 것이 먼저일 듯 하네요...
(비주얼베이직을 써보면 포인터가 왜 필요한지 이해하게 된답니다...ㅎㅎ)
머리가 아니라 가슴으로 이해를 해야(느끼는게 아닙니다..느낌은 가끔가다 틀릴 수도 있거든요..) 진정 알았다고 말할 수 있을 것 같습니다.

익명 사용자의 이미지

쉘의 symbolic 링크와 비슷하다고 생각하시면 됩니다.

익명 사용자의 이미지

아래글들중에 C의 pointer와 assembler의 address를 동격으로 취급하는 글이 있는데 제가 아는 바로는 좀다르것 같습니다.
예를 들면
int printf ( char *fmt , char *str);에서
printf는 pointer일까요 변수일까요.
보통 변수를 데이터라고 생각하겠지만 변수(variable)은 데이터일수도 있고 함수일수도 있습니다.

int (*ptr)(char *fmt , char *str);을 보면 금방알수 있죠.

ptr = &printf;
라고 쓸수있죠. 즉 ptr은 printf라는 변수르 가리키느 포인터인거죠.
이걸
ptr = printf;
식으로 쓰면 에서 납니다.

printf ( fmt , str );을 어셈으로 보면

push str
push fmt
call printf
이죠. 어셈블러 에서 보면 printf는 어들레스이지만
C에서 볼때는 pointer가아니라 변수입니다.

결론적으로 말하면
C에서의 변수는 어셈에서 데이터가 곳의 어드레스이고
pointer는 데이터가있는 곳의 어드레스를 가리키는 또다른 데이터에대한 어드레스 인거죠.

C포인터와 어셈의 어드레스는 다른 겁니다.
물론 완전히 다른것아니지만 개념이 다르죠.

어셈과 C의 관계를 알고나면 pointer는 매우 간단한 겁니다.
단지 compiler에게 더많은 정보를 주기위해 int *,char *등 변형을 많이 가해서 복잡해 진 것일 뿐이죠.

익명 사용자의 이미지

Anonymous wrote...
> ptr = &printf;
> 라고 쓸수있죠. 즉 ptr은 printf라는 변수르 가리키느 포인터인거죠.
> 이걸
> ptr = printf;
> 식으로 쓰면 에서 납니다.
에러 절대 안납니다.-_-;
C에서의 함수명 자체는 그 함수의 주소를 뜻합니다.
한마디로 &연산자를 적용시키나 안시키나 같단 말입니다.
그리고 printf가 변수라고 하셨는데, 절대 변수 아닙니다.
변수란 그 값이 변할 수 있는 값을 뜻하는데(프로그래머가 임의로)
함수는 컴파일러가 알아서 주소를 할당해 주는 것이지 프로그래머가
임의로 결정할 수 있는 것이 아닙니다.
이것은 마치 int a[100];에서 a가 변수가 아니라 상수인것과 같은 겁니다.

익명 사용자의 이미지

옳은 지적입니다. 잠시 제가 착가 했습니다.
ptr = printf
라고 해도 옳습니다.

그렇지만 뭔가 논리적으로 맞지 않다고 생각되지 않는지요.

예를 들어 보죠.

int foo ( char *msg , int i )
{
printf ( msg );
return i;
}

int (*func_ptr) (char *msg , int i);

int main ( int argc , char **argv )
{
//1)
func_ptr = foo;
func_ptr ( "hi\n" , 1 );

//2)
func_ptr = &foo;
func_ptr ( "hi\n", 1 );

//3)
func_ptr = &foo;
(*func_ptr) ( "hi\n" , 1 );

}

위에서 1),2),3)번 모두 잘 작동 합니다.
어느 것이 C에서의 pointer문법에 가장 일관돼게 적용되는 표현 일까요.
제가 보기에는 3)번 같은데....
물론 3가지 모두 잘 작동하기에 괜히 딴지 걸 필요는 없겠지요.
하지만 재미 삼아 함 따져 보기로 하죠.

1)번은 함수이름을 pointer로생각하면
func_ptr = foo; // 함수 포인터에 함수 포인터를 저장.
func_ptr ( "hi\n" , 1 ); // 함수이름은 포인터이고 이를 call할때
// pointer( args ...)형태이다고 보면.
는 옳은 표현 입니다.
하지만
foo 의 body선언과 func_ptr 선언이 서로 맞지 않습니다.
a)int foo ( char *msg , int i )
b)int (*func_ptr) (char *msg , int i)

a는 함수 선언이지만 일종의 변수 선언 형태를 하고 있습니다.
b는 분명 포인터 선언 형태죠.
문법상 일관성 없이 함수인경우는 이렇게 하기로 했다고 주장하면
전 할말 없습니다.
하지만 문법상의 일관성을 잃어버립니다.

변수 선언과 함수 선언은 다르다고 하시겠지만 assembler와 연관 시켜보면
별차이 없습니다.
static int a;
를 assembler로 보면 a 는 메모리상의 sizeof(int)크기 블락을 가리키는
어드레스로 변환됩니다.
int func( char *aa ){ printf (aa) }
는 func라는 함수 이름이 assembler로 func의 body부분이 들어있는 실행코드의 시작부분을 가리키는 address로 변환니다.
뭔가 비슷하지 않습니까?
제가 궤변을 하고 있나요? 판단은 여러분 몫입니다.
a = 1;
이 가능하다고 해서 a는 변수고 func는 변수가 아니고 상수에 가깝다고 하실수 있지만 a =1 도 assembler로 보면 a가 address로 바뀌므로 a라는address가 가리키는 내용을 1로 바뀌는 행동을 합니다.
a를 1로 바꿨다고 표현하지만 이건 assembler로 볼때 의미가 없는 표현 입니다. a란 address일 뿐이지 값을 저장할수 있는 것이 아닙니다.
a를 1로 바꿨다고 하는 표현은 C문법에서 가능한 표현이지만 assembler와 연관시키면 큰 혼란을 이르키죠.

assembler로 보면 변수 ,상수, 함수는 메모리상에 있는 코드/데이터에 대한 address입니다. 사실은 같은 거죠.
그렇다고 이걸 포인터라고 하지는 않습니다.

2)번을 보면 함수이름은 포인터라고 가정하면 func_ptr = &foo; 라는 표현이 말이 안됩니다. &foo는 함수형 포인터에 대한 포인터인데 이것을 func_ptr 함수형 포인터에 저장하는 건 문법상 말이 안되죠.
말이 안되지만 잘작동합니다.
단지 제가 하고 싶은 말은 문법상 일관성이 없다는 겁니다.

그럼 함수이름을 변수의 한 변형으로 가정하면 어떨까요.
func_ptr = &foo; 문법적으로 맞습니다.
그러나 func_ptr ( "hi\n" ,1 );이 문젭니다.
함수이름은 변수로 보기로 했으면 func_ptr이 포이터이므로
(*func_ptr)("hi\n" , 1)로 써야 문법의 일관성이 있지 않을까요.

위와 같이 따져 볼때 3)번이 포인터에 대한 문법상 일관성이 유지 되지 않을 까요?
3)번이 옳은 표현이라는 말은 함수 이름이 변수의 변형된 형태라고 가정할때 유효합니다.

전 제 경험상 함수를 변수의 한 변형된 형태로 봅니다.
문법도 함수 선언과 번수 선언이 비슷합니다.
int foo(char *msg) {}
int foo;
위는 함수선언이고 아래는 변수 선언이죠.
위 두 표현이 전혀 다른 표현일까요?
어차피 위 두 표현의 foo는 컴파일 하면 메모리상의 어떤부분을 가리키는 address로 변경됩니다.
단지 이리로 jump(함수인경우)하느냐 이것이 가리키는 데이터를 읽기/쓰기하느냐의 치이가 있죠.

제가 이상한 소릴 하고 있나요? 음...
전 그냥 제 생각을 적어 봤습니다.
많은 반론 부탁드립니다.

익명 사용자의 이미지

C언어 표준 문법상으로 저렇게 생략하고 쓰는걸 허용합니다.
즉, 어떤걸 선택하는지에 대한 것은 단지 프로그래머의 스타일 문제에 지나지 않는다는 겁니다.(char* str;와 char *str;의 문제와 같습니다)
다만, 사람이란게 한자라도 덜치는 쪽을 선택하기 마련이라, 1번이 인기가 좋을 뿐이지요.

익명 사용자의 이미지

저희 회사에서는 1번으로 씁니다만..

익명 사용자의 이미지

포인터도 변수다..
일반 변수와 마찬가지로..
단지 주소값을 저장할뿐이고..
주소에 위치한 값을 가져올수 있을뿐이다..

int *a; 보다 난 int* a;

를 선호한다.. 첫번째 표현식이
오히려 혼란을 가중 시킨다..

익명 사용자의 이미지

int* a, b;
라는 식에서 a는 포인터, b는 정수형이죠.
그래서 저는 int *a를 더 선호합니다:
int *a, b; //a는 포인터 변수, b는 정수형 변수

그러나 int *a 식의 표기를 일관적으로 밀고
나갈 수는 없겠더군요. int*로 표기해야 의미가
분명해지는 경우도 많으니까.
int[] a냐, int a[]냐도 비슷한 문제이고...
암튼 C는 아름다운 언어는 아니라는 생각이 듭니다.

knight2000_의 이미지

흠... 포인터 변수, 참조 변수, 일반 변수를 혼합하여 정의하거나, 선언하지 않도록 많은 글에서 권유하고 있습니다.

컴파일러가 해석하는 코드는 같으나,
일관성이 있는 코딩이 어렵고,
가독성이 낮은 코드가 만들어지죠.

GCC Coding Conventions 에서는 아래와 같은 코드를 권장하고 있습니다.
(원문은 http://gcc.gnu.org/codingconventions.html 입니다.)

!x
~x
-x (unary minus)
(foo) x (cast)
*x (pointer dereference)

위에서 보면, 캐스트 연산자를 제외한 단항연산자(unary operator)는 그에 따라오는 오퍼렌드에 붙여쓸 것을 권장하고 있습니다.

익명 사용자의 이미지

그래서 저는 항상...

typedef int* PINT;

PINT a, b;

이렇게 쓰죠. ^^

익명 사용자의 이미지

포인터를 이해하기 위해서는 하드웨어의 이해가 반드시 필요하다고 생각합니다.
적어도 해당 cpu의 memory addressing mode정도는 이해하여야 할 것입니다.
포인터 어렵지만 재대로만 사용하면 어셈블리가 부럽지 않죠~

익명 사용자의 이미지

많이.. 공부하다보면..
이해라기 보단 익숙해지죠..
익숙해지면 저절로 이해되고..
.. 저에 한에서는.. 말이죠..

익명 사용자의 이미지

포인터를 이해하는 확실한 방법으로
가장 좋은 방법이 마이크로프로세서 땜질해서...보드 만들어보고... 롬,램,및 주변회로
를 이해하고, 어떻게 메모리 및 주변기기에 데이터를 저장하고, 불러오는지 이해하면서
어셈으로 직접 프로그램을 짜보면 간단히
끝나는 문제임.

익명 사용자의 이미지

뉘미, 그게 간단히 끝나는 문제요?

kkung_의 이미지

Windows의 단축 아이콘으로..

이해했던 기억이 납니다.

가장.. 확실한 비유가 아닐까 하네요 =)

익명 사용자의 이미지

GOOD!!

Renn의 이미지

확실히 포인터는 가능한한 안쓰는 것이 좋습니다. 비록 여러가지 이점을 가져다 줄 수 있지만, 코드 이해력이 떨어지게 되는것은 어쩔 수 없는 문제이니깐요.

하지만, 적어도 C 언어의 경우는 포인터를 어쩔 수 없이 써야하는 경우도 많습니다. 대표적인게 call by reference를 통한 2개 이상의 값의 처리, list/tree/hashtable 등등의 자료구조 구현, 함수포인터를 이용한 핸들러 설정, 가변적인 배열을 대신할 동적메모리 할당 등 어쩔 수 없는 것들이 있습니다. 물론 C++에서도 dynamic-casting이나 virtual method 구현 등에서 포인터를 쓰긴 하지만 그다지 가독성 문제는 덜하지요. 그나마 reference(&)를 지원해 주기 때문에 C 보다 좀 더 편하다는 것이...

포인터를 쓰지 않을 수 있는 가장 좋은 방법은 역시 다른 언어를 찾아보는 것이겠죠. python이나 java와 C의 조합도 괜찮다고 생각되네요. (python 광신도로써;;;) 안되면 C++ 컴파일러를 통해 C++의 기능을 붙여서 만든 사이비 C 코드도 어떻게 보면 괜찮다는 생각입니다. (물론 C++을 쓸거면 객체지향으로 나가는 것이 더 효율적이지요)
--
Seo, Hee-Seung.
http://anitype.net/

익명 사용자의 이미지

하지만 포인터의 매력이라면 어마어마한 가능성이겠지요.
또 포인터 없이 자료구조를 표현한다면 넘 빡실거 같드는

요즘 자바를 쓰고 있긴한데 포인터 없으니까 환장하겠더라구요.

뭐 역시 모든 버그의 원인은 포인터라는 말이 있긴하지만도

그냥 포인터를 처음에는 약간의 시뮬레이터를 한다는 마음으로
간단한 리스트 소스를 분석해 보셔여
그럼 이해에 도움이 될듯

freerion의 이미지

저도 처음에 프로그램 시작할 때
포인터 때문에 눈물 많이 흘린 기억이 납니다.
저의 선택은... 너무나 간단했습니다.
저의 프로그램 철학이 있었기에...

간단합니다..포인터 안쓰면 되지..
그래서 저는 자바를 선택했습니다.
자바 만쉐이...

그러나, 4학년 들어 컴퓨터 구조를 배우면서 포인터에 대해 다시 알게 되었고..
포인터라는 개념이 없어 너무나 가까이 다가왔던 자바 마저도 내부적,의미적으로 포인터를 사용한다는 것을 안 지금..
포인터의 마력에 빠져 있습니다..

사족으로 덧붙이고자 하는 것은..
구지 책들에 나오는 어려운 기법은 필요 없다는 것입니다.
포인터의 포인터의 포인터 같은...
실제로 포인터의 개념은 하드웨어 프로그램(firm ware 나 8051-- 요즘은 툴이 잘 나와 있어서 어렵게 어셈 사용하지 않고 친숙한(??) 씨언어로 작업을 합니다.) 할때 많이 아주 많~~~이 사용합니다. 그래 봤다.. 어드레스 지정하는 거 하나 입니다.

뭐 제가 아직 다중 포인터를 꼭 써야만 하는 고급 프로그램을 해보지 않아서 그런지 몰라도
프로그램은 누구나 보고 알수 있게 쉽게 짜는 게 좋은 거 같습니다.
몇만분의 일초의 성능을 따지던 옛날 생각을 하면 안 됩니다...실제로 포이터 써서 어셈으로 작업 하는 게 성능은 월등 우세 합니다....

이상 헛소리 였습니다.

익명 사용자의 이미지

많은 분들이 글을 써주셨으니 별 할 말은 없지만...

꼭 하고싶은 말은 이겁니다.

"쉽게 생각하라. 어렵게 생각하면 더 어렵다."

요즘은 어셈블러 잘 안쓰지만 어셈블러가 포인터 이해엔 도움이 좀 된다고 생각합니다.

함수의 구현도 어차피 메모리에 올라가므로 시작주소가 있을거고 그게 함수의 포인터다 이런식으로 이해하시면 쉽지 않을까염

익명 사용자의 이미지

C언어에서 =의 의미는 어셈에서 MOV 또는 LD, ST로 직접 전송할수 있는 수준의 자료형만을 지원하고, 나머지는 사용자에게 맡깁니다.
따라서 기본 자료형과 어드레스는 MOV로 전송이 가능한 수치니 바로 대입이 되고요. 나머지는 안되죠. 기타 언어들도 주소만을 바꾸지만, 표현방식의 차이때문에 C보다는 쉽게 느껴지는 것 같습니다.

초창기에 문자열이나 배열들의 처리는... 난 몰라. 배째. 당신이 알아서 해. 그런 느낌을 받았습니다. 요즘은 그러려니 하지만요.

익명 사용자의 이미지

포인터에 대해 전혀?? 모르는 초보 라고
가정할 경우...제가 중학생때 보던 책을
추천합니다....(제가 중학생때 그러니까
10년도 훨씬 더 전에 출판 한 책이라 지
금도 구할 수 있는지는 잘 모르겠습니다
.)

책 이름은

" Mastering C Pointers " 입니다. 제목

그대로 포인터에 대해 기초부터..찬찬히
잘 가르쳐 주는 책입니다.

포인터 , 포인터의 포인터 , 배열의 포인터 ,
구조체 , 함수의 포인터 ..등등.. 포인터에
대해 기초적인 부분들에 대한 시원한 해답을
줄 것입니다.

- 트론의 유령 -

익명 사용자의 이미지

** 아직 이해못하는 부분..

1. void 포인터 ????

2. 함수 포인터 ????

누구 설명해 주실 분 안계신가요?

익명 사용자의 이미지

void형 포인터 : 포인터를 쓰다 보면 하나의 포인터 변수에 여러가지 타입의 포인터 주소를 번갈아가며 저장해야 될 때가 생깁니다. 이럴때 쓰는 것이 void형 포인터 입니다. 그냥 int나 char형 포인터 변수를 써도 되지 않겠냐고 생각할 수도 있겠지만... void형 포인터를 사용하면 형변환 같은 부분에서 언어적으로 약간의 지원을 더 받을 수 있습니다. (한마디로 범용 포인터) 먼 옛날에는 int형 포인터 또는 char형 포인터를 void형 포인터와 같은 역할로 사용했다고 합니다.

함수 포인터 : 만약 우리가 같은 타입(같은 형태의 매개변수, 같은 형태의 리턴타입)을 가지는 함수를 골라서 써야 될 경우가 있다고 칩시다. 이럴때 if 또는 switch문으로 쓸때마다 선택해서 쓰게 할수도 있겠지만, 함수 포인터가 있다면 좀 더 편리하게 일을 진행할 수 있습니다. 함수 포인터는 함수의 주소값을 저장하는 변수입니다. 함수 포인터에 함수의 주소값을 저장해 놓으면 마치 그 함수를 호출하듯이 함수 포인터를 이용해서 원래의 함수를 호출할 수 있습니다. 많은 C 컴파일러에서 지원해주는 qsort함수가 아주 좋은 예가 되겠습니다.
http://www.delorie.com/djgpp/doc/libc-2.02/libc_547.html
여기에서 보면 매개변수로 함수의 포인터를 받습니다. 이렇게 함으로써 임의의 크기를 갖는 변수를 정렬할 수 있도록 해주는 겁니다.

익명 사용자의 이미지

포인터가 아주 유용하게 많이 쓰이는 곳은
동적 메모리 할당을 한
구조체의 멤버변수의 참조용이겠지요.

그러나 포인터를 사용함으로 해서
그 부작용(side effect)도 만만치가 않아욤^^

포인터의 잘못 사용으로 버퍼오버플로우
발생을 유발하는 부실프로그램을 겨냥한
해커들의 공격..

익명 사용자의 이미지

함수형 프로그래밍에서는 함수가 딴 짓 하는 걸
사이드 이펙트라고 하죠.
메모리를 조작하는 행위가 대표적인 사이드
이펙트일 겁니다. - 사실 이런 의미에서 상당 수의
C 함수들은 함수가 아니라 프로시저라고 불러야
옳다고도 합니다.
안전한 프로그래밍을 위해서 각 객체는
자신이 책임질 수 있는 행위만을 하도록 규제되어야
합니다. - 함수형 프로그래밍의 근본 이념이죠.
C와는 극과 극이겠네요.

---삼천포였습니다.

익명 사용자의 이미지

포인터는 말 그대로 'pointer' 입니다.

-이쁘늬

익명 사용자의 이미지

고등학교때부터 독학으로 보던 c+알파
이젠 10년이 넘었는데도 가지고 있습니다.

그때 당시에 포인터에 대하여 가르쳐 줄 사람도
없었고 모르면 책 버려두고 술마시러 나갔죠

결국 앞부분만.. 시커멓고 뒷부분은 하얀 책으로 있었는데...

몇년동안 봤더니 어느 순간 이해가 가더군요.

그러다가 퍼즐인C인가... 여하튼 퍼즐이라는
제목이 붙는 c로된 문제집(원서)를 구했는데
포인터가 기본으로 3개씩 붙는 문제집이였습니다.

말그대로 퍼즐!!

몇번 보았더니 재미가 있더군요.

지금은 자바를 사용중인데, 레퍼런스라는
것이 이제 머리속에 붙어 있으니 어렵지
않게 사용하고 있습니다.

비트에서 c 문제를 내서 시험을 볼때
퍼즐inC에서 문제를 발최하여 시험본다고
알고 있습니다.

그러니 무지 어려울 수밖에 없지요.

하하

익명 사용자의 이미지

전형적인 함정 문제군요.

알다가도 모를 문제들.
컴파일러마다 답이 다른 문제들.
printf("%d %d %d", ++a, ++a, ++a);
참고로 정답은 "3 2 1"입니다.

C++같으면 가상함수의 상속 문제를 내겠군요.
패턴이 하나일때는 정답을 외워버리는 그만이지만,
잘못외우면 나중에 또 헤깔리죠.

실무에서 이런식으로 코딩하면 ... 미움받죠.
회사가 미우면 이런식으로 코딩해주면 되죠.
하지만 남아있을 불쌍한 동료들을 생각하면 쉽게 짜는게 좋겠죠.

익명 사용자의 이미지

printf("%d %d %d", ++a, ++a, ++a);
이건 쓰신대로 정답이 없는 문제 아닙니까?

일반적인 C 컴파일러에서는 함수의 매개변수를 오른쪽에서 왼쪽으로 평가하지만(내부적인 구현 방법과 관련이 있는 듯), C 표준에 의하면 어느 쪽 방향으로 평가해도 틀린게 아닙니다. 모님의 사이트에 있는 말을 그대로 옮기자면 다음과 같습니다.

인자의 평가순서 (the order of evalution of argument) 는 따로 정해져 있지 않습니다 (unspecified); 컴파일러마다 다르다는 의미입니다. 하지만 인자와 함수지정자 (function designator) 는 그 부작용 (side effect) 을 포함해, 함수에 진입하기 전에 모두 평가됩니다. 어떠한 함수라도 재귀호출 (recursive call) 이 가능합니다.

따라서 저런 코드의 결과를 묻는 문제는 절대로 출제해서는 안됩니다. 한다면 '다음중 사용할 때 이식성에 문제를 일으킬 수 있는 코드는?' 정도로 출제하면 모를까...

참고로, 위의 저 글은 http://c-expert.uos.ac.kr/ 여기서 퍼온 겁니다.

익명 사용자의 이미지

저의 불찰입니다. 지적 감사합니다.

int a = 0;
printf("%d %d %d", ++a, ++a, ++a);
참고로 정답은 "3 2 1"입니다.
-> 참고로 VC++에서라면 "3 2 1"입니다.

근데 ... 제가 신입때 모 회사에서 진짜로 이런걸 문제로 내서 저를 평가할려고 하더군요. "컴파일러마다 다름"이라고 쓸려다가, 상대방도 잘 모르는 것 같아서 '어떤 답을 원하는 걸까?' 고민하다가 답을 써냈더니 나중에 맞다고 하더군요. 뭐라고 썼는지 기억도 없지만... 맞췄는데도 별로 기쁘지 않더군요.

익명 사용자의 이미지

늘 이런 유혹을 느낀답니다.

저 개인적으로는 포인터를 어떻개 써도 그만이지만, 다른 표현의 필요성을 때때로 느낍니다.

예를들어 다음과 같은 코드가 있다고 할때
char *p;
p = (char *)mailloc(100);
*p = 'a';
*(p+1) = 0x00;

좀 바꿔서($addr) 표현해 보면 어떨까요?
char *p;
p$addr = (char *)mailloc(100);
(p )$data = 'a';
(p+1)$data = 0x00;

너무 무모한가요?

익명 사용자의 이미지

VAX 나 Alpha server system 사용하시는 분인가보군여....,^^
sys$qio( .... ) 나 lib$..... 하하 오랜만에 보는 즐거운 방식이네여

logout_의 이미지

예전에 나우누리 리동에 올렸던 글입니다. 참고 하시길.

----------------------------
re: 포인터 때문에 머리아프다

네. 머리 많이 아프죠.

제 경우는.. 이렇게 해결합니다. 항상 컴퓨터로 일을 하다보면
dynamic이라는 말이 중요하죠. 리눅스 커널의 경우는 윈도우자와는
달리 모듈이라는 '드라이버'를 쓰죠. 모듈로 사운드 카드를 잡는
걸 생각해 보면 차이는 자명합니다. 윈도우즈는 드라이버를 깔고
재부팅을 해야 하지만 리눅스 커널은 modprobe 명령으로 재부팅을
하지 않고 드라이버 설치, 인식을 끝냅니다. 아주 modular하죠.

이걸 다른 말로 보면.. dynamic이라고 얘기해도 됩니다.
포인터도 마찬가지입니다. 예를 들어서요... 초등학교의 한 반 출석부를
출력하는 간단한 c program을 짠다고 해 봅시다. 변수에다가
학생 번호, 이름, 주소 같은 정보를 배열로 짜야 되겠죠.

그런데... 고민이 생깁니다. 도데체 한반의 학생 숫자를 얼마로
잡아야 할까요? 50명은 너무 어중간하고... 100명으로 잡자니 메모리
낭비가 많은 것 같고... 좀더 일반적으로 생각하면 한 반의 학생
숫자가 정해진 게 아니니 골치가 아프죠.

학번을 저장하는 int 변수를 한번 생각해 보죠. 가장 속편하게
짜려면 이러면 좋을 겁니다. 프로그램 실행할 때마다 사용자한테
학생 수를 물어보면 만사 쉽게 해결이죠?

scanf("반 학생수는? %d\n", &n);

int hakbun[n];

요러면 좋겠죠? 그런데... 이 코드는 컴파일하면 아래 int hakbun[n]; 에서
컴파일 에러가 납니다.

컴파일러 입장에서는 에러를 내는 것이 당연합니다. 도데체 n이라는
변수를 써놓긴 써놓았는데... n의 크기는 프로그램이 실행되기 전까지는
알 수 없거든요. 따라서 컴파일러 입장에서는 hakbun이라는
변수에 얼마 크기의 메모리를 줘야 하는지 판단이 안섭니다. 초보
프로그래머는.. 이런 경우에 귀찮으니 int hakbun[10000]; 정도로
해서 쇼부를 보죠. :)

이런 경우는... 컴파일러에 이렇게 얘기를 해 줘야 합니다. static하게
메모리를 미리 잡아 놓으려고 하지 말고 대신에 dynamic하게 메모리를
늘였다, 줄였다 할 변수를 지정해 놓는 거죠. C에서는 이렇게 메모리를
dynamic하게 쓰기 위해서 포인터라는 방법을 씁니다.

포인터를 이용하면...

int *hakbun;

scanf("반 학생수는? %d\n", &n);
hakbun = (int *) malloc(n * sizeof(int));

요렇게 쓰게 되는 거죠. 맨 아랫줄이 좀 복잡해 보입니다만...
'int 타입의 메모리 저장용 공간을 n개 확보하고 메모리 공간이 시작하는
주소를 hankbun에 넘겨서 hakbun이라는 핸들을 통해서 메모리를
억세스 하겠다... 그런 얘기가 됩니다. malloc 앞의 (int *)는
hakbun이 int 타입의 포인터변수이기 때문에 malloc보고 헛갈리지
말라고 정확히 specify해 주는 것이구요.

포인터를 안쓰는 자바는 요렇게 하죠.

int hakbun[];
.....(중략).....
hakbun = new int[n];

당근 자바에서도 int hakbun[n]; 과 같은 선언은 컴파일 에러가 납니다.

반드시 int hakbun[]; 이렇게 dynamic하게 메모리를 쓰겠다고 컴파일러에
알려 준 다음 실제 써먹을때는 new라는명령어를 통해서 써먹는 겁니다.

이런 식으로 하면... 한 반의 학생수가 1명이든 2명이든, 100명이든
1000명이든 메모리가 허락하는 한 runtime에'내맘대로' 학생 수를 잡아
줄 수 있는 프로그램을 짤 수 있는 겁니다.

이걸 dynamic memory allocation이라고 하는데... 굳이 포인터가 아니더라도
프로그래밍을 하면 어디든지 나오게 되어 있습니다. java같이
포인터를 안쓰는 언어는 객체지향적인 문법으로 얘기를 해 주고
C나 C++은 포인터라는 문법을 쓸 따름입니다. perl도 자세하는 모르지만
reference라는 방식을 통해서 이런 dynamic memory allocation을
프로그래머 입맛대로 쓸 수 있게 해 주는 걸로 알고 있습니다.
펄 정도만 되면... 그런 걸 생각안하고 프로그래밍을 해도
왠만한 일은 다 처리가 됩니다만.

여하간 이런 식으로... 컴퓨터에서 dynamic이라는 단어는 중요하게
생각해 볼 필요가 있습니다. 모듈, 포인터, 동적 공유 라이브러리,
이런 것들이 모두 dynamic이나 modular라는 단어가 지칭하는 개념하에
들어갑니다.

포인터 문법에 너무 신경쓰지 말고 포인터를 왜 쓰는지 차근해 보면
프로그래밍에 많은 도움이 될겁니다. 제 생각으로는 malloc을
제대로 이해하는게 프로그래밍에서 아주 중요한 고비라고 생각합니다.
제가 대학 컴퓨터 개론 수업을 담당한다면... malloc에 대한 문제는
기말고사에 반드시 낼 것 같습니다. :)

도움이 되었는지 모르겠네요. 그럼~

logout_의 이미지

추가해서 몇개만 더 적을께요.

다음과 같은 함수를 생각해 보죠.

int foobar(int a)
{
return (a+1);
}

C에서는 함수 호출시에 call-by-value를 사용합니다. 다른 곳에서 output = foobar(input); 이라고 이 함수를 호출했다고 합시다. 이렇게되면 input 변수의 값이 그대로 복사되어서 foobar함수로 들어가고 계산 결과값이 return문에 의해서 다시 output 변수로 들어갑니다. 그럼 푸바 함수를 호출하기 위해 사용되는 메모리는 몇바이트일까요? 혼동을 피하기 위해서 함수 파라메터와 관련되는 input 변수와 a변수만 살펴보죠. 일단 int타입이 2바이트를 잡아먹는다고 가정하죠.

우선 호출하는쪽에서: input 2바이트
함수내부에서: input이 a로 '카피'되면서 2바이트

따라서 도합 4바이트가 필요합니다.

이게 간단하게 int나 double정도만되어도 상관이 없습니다. 그런데 다음 경우는 문제가 생기죠.

int foobar(a_large_size_structure a);

마찬가지로 이 푸바 함수도 다음과 같이 호출했다고 합니다.

output = foobar(input);

만약에, a_large_size_structure 타입의 변수 하나가 그 안에 많은 정보를 갖고 있어서 간단한 int와는 달리 변수 하나가 10Mbyte를 잡아먹는다고 가정하죠. 이 경우에 함수 호출시 파라메터와 관련되어 사용되는 메모리의 양은요?

마찬가지입니다. 10Mbyte + 10Mbyte 해서 도합 20메가바이트가 듭니다.

조금 더 자세히 보면 일이 만만치 않다는 것을 알 수 있습니다. output 변수도 결국은 input과 같은 타입이므로 10메가바이트를 더 잡아먹겠지요. 이런 식으로 나가다가는 메모리 낭비가 장난이 아닙니다.

이런 경우에 포인터를 써 보죠.

void foobar_ptr(a_large_size_structure *a);

호출은 이렇게 하면 됩니다.

foobar_ptr(&input);

foobar_ptr 함수는 포인터를 사용하고 있기 때문에 내부적으로 포인터가 가리키는 input 변수 내용을 직접 억세스 해서 필요한 작업을 수행하면 그만입니다. 포인터를 쓰지 않았을 경우는 일단 '똑같이 생긴 변수를 하나더 카피해서 만들고' 그 다음에 '카피본에 수정을 가하고' 마지막으로 '카피본을 통째로 리턴해서 새 변수에 다시 복사시킨다'의 작업을 수행하게 되는 것이죠. 프로그래머의 입장에서는 포인터를 쓰는 경우나 포인터를 쓰지 않는 경우나 로직은 똑같이 느껴집니다.

자바를 보면 int, float, double과 같은 primitive type들은 모두 call-by-value 방식으로 변수가 처리됩니다. 그러나 사이즈가 커질 가능성이 있는 객체들은 무조건 레퍼런스로 처리됩니다. 다음 예제를 하나 더 보죠. 자바문법이기는 하지만 이게 이해는 쉬울겁니다.

int a = 1;
int b;
b = a; // a의 값을 b로 복사
a = 2; // a는 2, b는 여전히 1입니다.

객체의 경우는
Integer a = new Integer(1); // a 객체를 새로만들고 이것을 1로 초기화
Integer b;
b = a; // a의 값을 b로 복사
a.increment(); // a 값을 1 증가

a.printValue(); // 2가 출력
b.printValue(); // 마찬가지로 2가 출력

핵심은 b = a; 입니다. 첫 예제의 b = a;는 a변수의 '값'이 b로 한카피 더 복사되는 것이고 두번째 예제는 a변수에 담긴 '포인터 주소의 값'이 b 변수로 한카피 더 복사되는 것입니다. 자바에서는 객체를 담고 있는 변수는 무조건 레퍼런스로 생각하기로 했으니까 결국 call-by-value로 변수값이 복사된 것 같이 보여도 주소가 복사되는 바람에 두개의 변수가 똑같은 객체의 위치를 가리키는 일이 벌어진 겁니다.

파이썬은 자바나 C와는 달리 모든 변수가 reference입니다. 파이썬을 배울때 초반에 이게 약간 사람을 헛갈리게 할 수 있습니다. 다만, 파이썬의 경우는 원래부터 객체지향을 잘 구현해 놓은 언어라서 오히려 일관성이 있어 좋습니다.

아까 제가 올린 글에서도 얘기를 했습니다만 포인터의 가장 큰 필요성은 동적인 메모리 할당입니다. 특히, 최근처럼 사이즈 큰 객체들을 선언문 하나로 덜렁덜렁 불러 쓸 수 있는 프로그래밍 환경에서 포인터의 이해는 필수입니다. 포인터, 적어도 레퍼런스의 개념은 갖고 있어야 메모리를 dynamic하게 쓸 수 있습니다. 어떤 언어를 쓰던 간에 이 동적 메모리 할당의 기법은 언젠가는 넘어야 하는 산입니다. 차근히 잘 배워 두세요. C의 포인터 문법이 사실 복잡해 보이기는 하지만 동시에 상당히 유연합니다. 오히려, 자바의 레퍼런스 개념은 얼핏 보면 쉬워 보이는데 막상 제대로 쓰려면 쉽지가 않습니다.

익명 사용자의 이미지

>자바를 보면 int, float, double과 같은 primitive type들은 모두
> call-by-value 방식으로 변수가 처리됩니다. 그러나 사이즈가 커질
> 가능성이 있는 객체들은 무조건 레퍼런스로 처리됩니다.

바늘에 찔리는 듯한 느낌...
JAVA에서 값/주소에 관한 가장 핵심적인 설명인 것 같습니다.

자바는 일반타입과 클래스타입을 내부적으로는 다르게 처리하면서, 외부적으로는 같은 표현을 쓰죠. 당장은 쉽지만 결국 이 미묘한 차이를 읽어내지 못하면 자바가 어려워지죠.

익명 사용자의 이미지

C 책 보면, 컴퓨터 언어쪽이 대개 쉽기 때문에
폼 좀 잡아 보려고 포인터를 일부러 어렵게
표현해놓고 있습니다.

하지만, 포인터 별 거 아닙니다.
번지를 이용한다 그게 전부입니다.

책의 예제에 나오는 그런 꼬인 포인터는
거의 쓸 일도 없습니다.

그냥 쉽게 생각하십시오.

익명 사용자의 이미지

'포인터 좋아하면 포인터로 망한다'라는 속담이 있던가요?

포인터를 쓸 수 밖에 없는 알고리즘이 아니라면 포인터는 피하는게 좋죠.
게다가 다른 개발자들과 코드를 공유해야 한다면 더더욱 포인터는 자제하는게 좋을 듯 합니다.

다만 포인터를 확실하게 알고 있어야 하는 이유는 남들이 쓴 포인터 정도는 어느정도 이해해야 하니까요.

포인터의 포인터라던가, 함수의 포인터는 아주 특별한 경우가 아니라면 쓸 일이 없죠. 이 정도를 쓰는 알고리즘이라고 하면 자료구조나 커널, 핵심 엔진등등...

익명 사용자의 이미지

C를 사용해야 하는 분야에서라면,
이미 포인터는 필수 아니가요?

익명 사용자의 이미지

꼭 필요한 곳에서 만 사용하자는 소리 같은데요~

일단 덩치가 작으면 그냥 포인터 사용해도
코드가 그리 길지 않으니 디버깅이 그렇게
곤란하지 않을것입니다. 허나 좀 길어진다
싶으면 그때는 정말 뭐가 뭔지 모르겠고,
버그의 시작이 어디서 인지 모르겠더군요.

우리가 체감 할 수 없을 정도의 속도 개선을
위해 골치아프게 포인터 사용해가며 프로그램
만들 필요는 없다는 거죠.

-영희-

익명 사용자의 이미지

도와주셔서 감사합니다. 꾸벅~

예를들어
100명이 넘는 인력이 동시에 개발중이고,
각각의 개성이 제 각각이고,
6개월후에는 이중 30%는 다른 인력으로 바뀐다고 가정할때,

결론적으로
동료이 알기 쉽도록 직관적으로 코딩해주는것이
최소한의 코딩의 예의가 아닐까 생각합니다.

저는 아직도 간혹 동료들이 제가 짠 코드를 인쇄해서
칼들고 쫒아오는 꿈을 꾼답니다.

bookworm_의 이미지

제 경우는 어셈블리어를 익힌 후에 C를 익혀서
포인터 개념이 쉽더군요.

오히려 당연한거 아냐라는 의문이 들정도로...

포인터가 잘 이해가 안되시면 어셈블리어를
공부해보세요. 왜 포인터를 쓰는지 쉽게
이해가 되실겁니다.
--
- B/o/o/k/w/o/r/m/ -

Bookworm

익명 사용자의 이미지

프로그램의 발달순서를 보면?(오히려 퇴화?)
어셈블리어->C->C++->java
대충이렇죠...
근데 여기서 보면 포인터라는 개념을 점점더 안사용하는 방향으로 발전하네염...?
즉 포인터가 프로그램에서는 아주 아렵다는 거졈...
근데 기계어에 가까운 프로그램일수록 속도가 훨씬 빨라지죠... 즉 포인터를 잘 사용해야 좋은 프로그램을 만들수있다는 의미... (여기서 좋은 프로그램은 경제적인 요소는 제외한다...) 메모리공간을 잘 이용할수록 컴퓨터를 효과적으로 빠르게 사용할수있습니다...
프로그래머라면 포인터는 제대로 알아야된다고 봅니다.. 저두 맨날 이 포인터에서 해매는데... 계속 하다보면 익숙해지겠졈...T T;;;애거...

페이지

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.