포인터 문제중에....
글쓴이: fliers / 작성시간: 수, 2003/10/22 - 9:32오전
char s[100];
char *p;
라고 돼 있을때 틀린것 찾는건데,
1. s=p;
2. p=s;
3. *p=*s;
4. *s=(*p++);
처음에 1번은 되는건줄 알고 생각도 않하고 넘어갔었는데 1번이 답인것 같더군요.
s 주소에 p 주소를 넣는다 같은데 뭐가 틀렸는지 모르겠네요..
s가 배열로 선언돼 있는건데 p가 들어오면서 배열이 깨지나요?
File attachments:
첨부 | 파일 크기 |
---|---|
배열강좌5-3.gif | 9.27 KB |
배열강좌5-2.gif | 15 KB |
배열강좌5-1.gif | 14.9 KB |
Forums:
배열 변수명은 아예 그자체가 (배열의 내용이 아닌) 상수인 포인터라고 생
배열 변수명은 아예 그자체가 (배열의 내용이 아닌) 상수인 포인터라고 생각하시면 편합니다. 상수는 값을 변경 못하니까 상수 포인터도 가리키는 주소값을 변경 못하는 것이라고 생각하시면 됩니다.
배열은 3번째와 마찬가지라고 보시면 되겠습니다. 각각의 차이점을 조사해보시면 도움이 되실 것입니다.
그리고, 위 문제는 문구중에 문법만으로라는 단서 조항이 있어야 합니다. 그런 말이 없다면 진짜 맞는 것은 2번밖에 없군요.
감사합니다.. 그렇게 생각하니깐 좀 낫네요.. :)
감사합니다.. 그렇게 생각하니깐 좀 낫네요.. :)
[quote="bugiii"]배열 변수명은 아예 그자체가 (배열의 내용이
첨언하자면, 대입 연산자 '='의 왼쪽 항에 올 수 있는 것은 modifiable lvalue 뿐입니다. 배열 이름은 lvalue이지만 modifiale lvalue가 아니기 때문에 대입 연산자의 왼쪽 항에 올 수가 없습니다.
그리고 배열 이름은 다음 세가지 경우를 제외하고는 항상 그 배열의 첫번째 원소를 가리키는 포인터 주소 값으로 자동 변환 됩니다. 이 특성 때문에 보통 '배열 이름은 포인터 상수다'라고 설명을 하곤 합니다.
* sizeof 연산자의 피연산자 - int array_int[5]; sizeof(array_int);
* 번지 연산자의 피연산자 - int array_int[5]; &array_int;
* 문자형 배열 초기화에 사용되는 문자열 상수 - char str[] = "abcde";
참고로 3번째 경우에 대해 설명을 하자면, "abcde" 와 같은 문자열 상수(string literal)도 배열 이름과 비슷한 특성을 갖습니다.
strcpy(buffer, "abcde");
여기서 strcpy함수의 두번째 매개변수로는 "abcde" 중에서 a를 가리키는, const char *형의 포인터 주소값이 넘어가게 됩니다. 다만 위에서 설명한 대로, 문자형 배열 초기화에 사용되는 문자열 상수는 strcpy와 비슷한 동작을 보입니다. 배열 안에 자신의 내용을 복사하는 거죠.
아닙니다. 1번을 제외하고는 모두 맞는 문장이며, 실제로 쓰일 수 있습니다.
2번은 s가 그 자신의 첫번째 원소를 가리키는, const char *형 포인터 주소값으로 변형되기 때문에 당연히 허용 됩니다.
3번은 p가 가리키는 char형 변수에다가 s의 첫번째 원소의 값을 대입하라는 뜻입니다. s가 "abcde..."였다면 p가 가리키는 char형 변수에는 'a'가 들어가게 되겠죠.
4번 또한 아무 문제 없습니다. s의 첫번째 원소에다가 p가 가리키는 char형 변수의 값을 대입하고, 포인터 p의 값을 1 증가시키라는 구문입니다. 물론 여기에는 전제조건이 있는데, p = malloc(n); 또는 char t[100]; p = t; 와 같은 구문이 중간에 끼어 있어야 한다는 것입니다.
[quote="lsj0713"]그리고 배열 이름은 다음 세가지 경우를 제
어떠한 방법을 사용하든 올바른 규칙을 익히면 상관 없다고 생각합니다만,
개인적으로는 포인터 "상수" 라는 개념에 다소 반감을 가지고 있습니다. C
에서 "상수" 는 메모리에 존재하지 않습니다 (그렇다고 약속합니다). 배열
은 분명 메모리에 존재하는 개체이며, 그러기에 포인터 연산에 관련되어 그
요소가 modifiable lvalue 가 될 수도 있습니다.
넵, 더 리얼(?)하게는,
#define num2hexdigit(i) ("0123456789ABCDEF"[i])
도 가능합니다.
간단히
char t; p = &t;
여도 됩니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
[quote]어떠한 방법을 사용하든 올바른 규칙을 익히면 상관 없다고 생
배열의 요소들은 메모리에 존재하는 개체지만,
배열의 이름(즉, 배열의 첫번째 원소를 가리키는 포인터)은
상수로 사용되지 않는지요 ?
그래서 배열의 이름은 modifiable lvalue가 안될것 같은데,
그 이유로 첫번째 명령이 안되는 것 아닌가요 ?
바이너리 코드를 확인해본적이 없어서 -_-;
자세한 설명을 부탁드리겠습니다. ^^;
데브피아의 옹언욱님 강좌란에서 발취했습니다[quote]----
데브피아의 옹언욱님 강좌란에서 발취했습니다
-------------- 다시 읽어보고 글 수정합니다 -_-;;------------
cTest를 보면 자체가 주소값 이기때문에 L-value로는 쓰이지 못하는게 아닌가 싶네요
예를 들면 12345 = 456; 이렇게 대입 못하듯이요
따라서 상수로 볼수 있는게 아닌가 싶네요
C언어 책에도 상수처럼 쓰인다 -_-;라고 자주 언급되어집니다
이건 보는 사람관점에 따라 달라질수 있는 문제긴 하지만요
승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스
[quote="vacancy"]배열의 요소들은 메모리에 존재하는 개체지만
"바이너리 코드" 를 확인할 정도로 low-level 로 간다면 C 언어의 거의 모
든 개념이 사실상 무의미해집니다 - C 언어의 정의는 "추상적" 관점에서 관
찰한 C 프로그램의 행동입니다.
제가 개인적으로 "포인터 상수" 라는 개념에 반감을 갖는다고 말씀드린 것
은 "포인터 상수" 라는 개념을 갖고 있다는 사실 자체가 실제 프로그래밍
과정에서 큰 잘못을 낳는다는 뜻으로 드린 말씀은 아닙니다. 다만, "포인터
상수" 라는 개념이 "상수" 의 의미를 포함하기에 C 언어의 lvalue 에 대한
개념을 이해하는 과정에서 방해가 될 수 있다는 지극히 "교육적인" 입장에
서 드린 말씀입니다.
예를 들어, 어떤 분이 언급하신 것처럼
가 허락되지 않는 이유가
100 = 200;
가 허락되지 않는 것과 동일하다면,
위는 허락되고 아래는 허락되지 않는 이유를 설명할 길이 없어집니다. 또한
배열 이름이 포인터 수식에서 단지 첫번째 요소의 주소값인 "포인터 상수"
일 뿐이라면, &a 의 type 이 pointer to "array" of int 라는 사실을 설명
할 길도 없어집니다 - 즉, "array" 의 의미를 그대로 보존하는 것이 가능하
다는 사실을 설명할 수 없습니다. 배열은 modifiable lvalue 는 아니어도
lvalue 입니다. 그리고 상수는 lvalue 가 아닙니다 (물론, C99 에 와서 그
경계가 엉터리가 되었습니다만). C 언어의 lvalue 는 일반적인 프로그래밍
언어에서 사용하는 lvalue 와는 다른 개념으로, 일반적인 lvalue 에서 'l'
이 "left" 를 의미한다면, C 언어에서 lvalue 의 'l' 은 "locator" 를 의미
한다고 이해하는 것이 언어를 자연스럽게 따라가는데 유리합니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
C++에서는int* const p = 50;에서 언어 차원에서
C++에서는
int* const p = 50;
에서 언어 차원에서 p가 상수 포인터가 되듯이
int A[50]; 에서 A가 상수 포인터로 인식된다고
생각하는것도 오류가 되나요??
저는 그러한 관점에서 접근한건데.. --;
승자는 자기보다 우월한 사람을 보면 존경심을 갖고 그로부터 배울 점을 찾지만 패자는 자기보다 우월한 사람을 만나면 질투심을 갖고 어디 구멍난 곳이 없는지 찾는다.
- 하비스
[quote="mastercho"]C++에서는int* const p
언젠가 han.comp.lang.c 에서도 같은 내용을 말씀드린 적이 있습니다만,
"호박 고구마" (호박 맛이 나는 고구마) 와 "고구마 호박" (고구마 맛이 나
는 호박 - 이런 게 진짜 있는지는 모릅니다 ;-) 이 다른 의미를 갖듯이,
"포인터 상수" 와 "상수 포인터" 역시 다른 의미를 갖습니다. 그리고 저는
"포인터 상수" 라는 설명 (그래서, 배열에 이루어지는 대입이 다른 상수에
이루어지는 대입과 "마찬가지" 이유로 허락되지 않는다는 생각을 끌어낼 가
능성이 있는) 에 대해 제 의견을 말씀드린 것입니다.
그리고, "포인터 상수" 라는 생각 역시 (교육적인 관점에서 바람직하지는
않아도) "오류" 라고 생각하지는 않습니다 - 겉으로 보이는 동일한 현상을
추상적인 단계에서 해석하는 방법의 차이일 뿐이라고 생각합니다.
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
[quote="전웅"]간단히[code:1]char t; p = &
포인터가 가르키는 것이 배열이 아니라 t형 변수일 때에도, 그 다음의 공간을 가리키는 것이 허용이 되는지요? 배열이나 malloc로 할당된 공간의 경우에는 허용된다고 알고 있는데, 그냥 일반 변수일 경우에도 허용이 되는 것인지 알고 싶습니다.
[quote="mastercho"]cTest를 보면 자체가 주소값 이기
전웅님이 말씀하신 것처럼, C99에서의 lvalue는 좌변값이 아니라 Locator value 입니다. 기존에 쓰이던 용어인 좌변값에 해당하는 것은 C에서는 modifiable lvalue로 보는 것이 타당합니다.
용어 자체가 그렇게 크게 중요하다고는 할 수 없겠습니다만, C 표준 문서에는 배열 이름이 lvalue라고 분류되어 있습니다. 누군가 "C 표준문서에는 배열이 lvalue라고 나와있던데?"라고 묻는다면 어떻게 설명해야겠습니까?
[quote="lsj0713"][quote="전웅"]간단히[cod
네, 가능합니다. 단일 대상체는 포인터 연산에서 1 의 크기를 갖는 배열과
동일하게 다루어집니다. 이 내용이 어디에 있는가하면... 음... C90 의 6.3
expression (C99 의 6.5) 의... 음... additive operatior 설명을 보면...
음... 포인터 연산에 대해 구구절절 긴 설명이 있는 부분의 첫 부분에
"단일 object 는 크기 1 의 배열과 동일하게 다룬다"
라는 식의 비슷한 이야기가 있을 것입니다.
p.s. 자료를 노트북으로 모두 옮겨 놓앗더니, 데스크탑에 앉아서 할 수
있는 일이 거의 없군요. :-(
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
[quote="mastercho"]C++에서는int* const p
C와 C++에서는 const의 생각을 약간 달리하셔야합니다. readonly(C)이냐, constant (C++) 이냐의 성격을 지닙니다.
제가 이해하기로는 readonly인경우, object가 항상 생성되는 것이며(C에서), C++에서는 기본적으로는 readonly object가 생성되겠지만, constant hint를 주기 때문에 최적화시에 그 pointer를 reference하지 않을 경우 object에서 공간을 차지하지 않고, 바로 사용되는 곳에 embed 되어버립니다.
물론 C 컴파일러에서도 reference하지 않는다면 object를 생성하지 않을 수 있습니다.
이와 같이 과연 배열 이름을 나타내는 값이 어떤 주소에 할당되느냐 안되느냐의 문제를 알기위해 예를 드는 프로그램들은 대개 pointer를 찍어보는 것 때문에 이런 최적화가 무시될 수가 있습니다.
실제로 배열을 상수 포인터라는 개념으로 이해하는 것은 타당합니다. 다만, 그 상수라는 개념이, "pointer를 취하는 일이 없다면 object로 만들지 않을 수 있다." 를 내포할 때만, 그렇게 이해하는 것이 좋다 생각됩니다.
---
http://coolengineer.com
[quote="pynoos"][quote="mastercho"]C++에서
C 표준에서는 실제적인 구현 방식에 대해 어떠한 제한도 하지 않고 있습니다. 의미적으로 표준이 보장한 바와 같은 동작이 이루어지도록 보장만 한다면, 내부적으로 어떠한 최적화를 하더라도 상관이 없습니다. 따라서 최적화의 관점에서 C를 이해하려는 시도는 의미가 없습니다. 애초에 아무것도 보장된 바가 없기 때문입니다.
저는 이 예제가 대체 무엇을 위한 예제인가 하는 의문이 듭니다.
위에 제가 쓴 글에서 나왔듯이, 배열 이름은 3가지 경우를 제외하고는 그 배열의 첫번째 원소를 가리키는 주소로 자동 변환이 됩니다. 따라서 cTest는 '0'을 가리키는 포인터 주소값이 됩니다. 반면에 &cTest는 3가지 경우에 해당하므로 배열 전체를 가리키는 포인터 주소값이 됩니다.
위 코드의 결과물은 C의 내부적인 구현 방식과는 전혀 관계가 없고, 어느 환경에서나 항상 같은 결과물이 나오는 그런 코드입니다. (물론 주소값이나 주소값의 출력 방식 등등은 환경에 따라 차이가 있을 수 있겠지요.)
그리고 아래의 설명은 틀렸습니다.
cTest는 배열의 첫번째 원소를 가리키는 포인터 주소값이고, &cTest는 배열 전체를 가리키는 포인터 주소값입니다. 같은 주소값이지만 가리키는 방식이 서로 다릅니다. 타입으로 설명하자면 char *형과 char *[]형이라 할 수 있습니다.
한가지 더 지적하자면, printf 함수에 전달하는 포인터 주소값은 항상 void *형으로 형변환을 해서 넘겨줘야 합니다.
[quote="lsj0713"][code:1]char *pTest=
알려져서는 안 되는 엉터리 예제입니다.
pTest 와 cTest 는 같은 결과가 보장되지만, &pTest 와 &cTest 는 그렇지도
않습니다 - 서로 다른 type 입니다.
추가로 한가지 더 지적하자면, 대응하는 conversion specifier 는 %p 여야
합니다. 이곳의 글이 그쪽으로 넘어가면 유용할 수 있지만, 그쪽 글이 이쪽
으로 넘어오면 득보다 실이 많은 듯 합니다. :-(
--
Jun, Woong (woong at gmail.com)
http://www.woong.org
[quote]pTest 와 cTest 는 같은 결과가 보장되지만, &
굳이 변명하자면, 제가 글을 작성할 때 글의 뜻이 제대로 전달되지 않도록 엉터리로 쓴 것 같습니다. -_-;; 제 언어 능력에 뭔가 문제가 많은 듯 합니다. -_-;
그 부분은 &pTest와 &cTest가 같은 결과를 가진다는 뜻이 아니었습니다. 그것보다는 그 예제 코드가 뭔가 내부적인 동작원리를 보여주기엔 부적합한 코드였다는 뜻이었습니다. 추상적인 동작 원리 만으로도 설명이 가능한 코드이고, 뭔가 내부 구현이나 동작 환경이 달라진다고 해서 다른 결과가 나오는 코드가 아니기 때문입니다.
그리고 %p 부분에 대해서는... 제가 %x를 %p로 잘못 본 결과였습니다. -_-;; 이놈의 대충 읽는 습관을 고쳐야 할텐데...
이미 논의가 끝난 문제에 또다시 답글을 달게 되어 죄송합니다만... hc
이미 논의가 끝난 문제에 또다시 답글을 달게 되어 죄송합니다만... hclc에 올라온 글을 보던 도중에 이 주제와 관련된 예제 코드가 생각나서 다시 글을 올리게 되었습니다.
배열 이름을 포인터 상수라는 개념으로 보는 것이 바람직하지 않은 이유를 제시합니다.
"배열 이름은 포인터 상수이다"라는 설명만으로는 위의 코드에서 **p가 왜 문법적으로 옳은 코드이며 **p의 값이 123인지 설명할 수 없습니다. p가 pointer to array of int[4] 이므로 *p는 array of int[4]가 되는데, 그럼 **p에서 array에 *를 붙이는 것이 대체 무슨 의미가 있겠습니까?
오로지 "array(혹은 array의 결과값을 갖는 수식)는 sizeof 연산자의 피연산자, & 연산자의 피연산자, char형 배열의 초기화에 쓰이는 문자열 상수일 때를 제외하고는 항상 그 첫번째 원소를 가리키는 포인터로 자동 변환된다"라는 설명만이 이 코드에 대한 설명을 할 수 있습니다.
[quote]bugiii 씀: 그리고, 위 문제는 문구중에 문법만
'문법적'으로 라는 단서조항이라고 말씀드렸는데, 앞말을 싹뚝 잘라버리시면... 3번 4번의 경우 거의 확실하게 segment fault 가 나지 않을까요? 그런 점을 말씀드린건데 설명이 부족했습니다.
그리고 배열을 포인터와 유사한 개념으로 생각하는 것이 편하다라고 ('이다'가 아니라는) 말씀드렸는데, 추가적인 설명이 없다보니 여러 답변들이 나온 것 같습니다만, 오히려 훌륭한 답변으로 좋은 것 또 배우고 갑니다.
댓글 달기