[질문] C 이중포인터 상수화 ~ ㅡㅡa
안녕하세요 자료구조를 공부하다 처음으로 이중포인터에서 상수화 할때 이상한 문제가 있다는 것을 알게 되었
습니다. 그런데 왜 이런 에러가 발생하는지 제 지식으로는 알 수 없어 이렇게 질문을 올립니다.
먼저 제가 구현한 프로그램에서 함수의 인자로 이중포인터를 상수화 하여 보호할 필요가 있어서 이중포인터
를 상수화 한 후 인자에 이중포인터를 주었더니 아래와 같은 에러 메시지가 나옵니다.
일단 제가 구현한 함수와 함께 보여드리겠습니다.
#include "sasmatrix.h"
#include
#define ROWS 8
#define COLS 7
int main(void) {
//
// 변수 선언
//
int** sm = smCreate(ROWS, COLS);
linkedList_h *L = createLinkedList_h();
//
// 희소 행렬 값 입력
//
sm[0][2] = 2;
sm[0][6] = 12;
sm[1][4] = 7;
sm[2][0] = 23;
sm[3][3] = 31;
sm[4][1] = 14;
sm[4][5] = 25;
sm[5][6] = 6;
sm[6][0] = 52;
sm[7][4] = 11;
//
// 희소 행렬을 단순연결리스트에 입력
//
여기가 그 문제의 함수 입니다.-->> if(smToTerm(sm, L, ROWS, COLS) == FALSE) ERROR(INSUERR);
//
// sm 포인터 변수는 smCreate(const int row, const int col) 함수에서 메모리 동적 할당을 받은 변수이므로 메모리 해제
//
free(*sm);
free(sm);
return 0;
}
원형은 errno_t smToTerm(const int** sm, linkedList_h* L, const int row, const int col)
이렇습니다.
그럼 에러메시지가 'smToTerm' : cannot convert parameter 1 from 'int **' to 'const int **'
이렇게 나옵니다.
int **이 변수를 const int **로 변환 불가하다는 내용인데요 ... 일반적으로 int * 변수를
const int *의 인자로 주어도 이상없이 작동하는데 왜 이중 포인터 일때만 이러한 메시지가 나오는지
이해가 가리안네여 ~ 도와주세여 ~!!
compiler 는?
그런데 const 를 상당히 착실히 하시는군요.
좋은 습관이긴 한데 Java 이상의 추상화 언어할 때 왠지 적응하기 힘들게 하더군요.
허전하달까, 왠지 불안하달까...?
두 다리 건너는(?) 경우는 안된다고 하는군요..
C++ 기초 플러스에서 읽었던 내용이 언뜻 생각나서 다시 찾아봤는데요, 다음과 같은 내용이 있네요...
-------------------------------------------------------------------------
(int * 변수를 const int * 변수에 대입하는 예가 나온 후...)
const와 const가 아닌 것을 이런식으로 섞어서 사용하는 포인터 대입은 두 다리 건너는 간접 지시인 경우에는 더 이상 안전하지 않다. 만약 그것이 허용된다면 다음과 같은 것도 가능하기 때문에 안 된다.
const int **pp2;
int *p1;
const int n = 13;
pp2 = &p1; // 허용되지 않지만 허용된다고 가정하면
*pp2 = &n; // 둘 다 const인데 p1이 n을 지시하게 만든다
*p1 = 10; // const n을 변경하게 만든다.
----------------------------------------------------------------------------
즉 int **를 const int **로 대입하는 게 가능하다면 const int를 간접적으로 변경할 수 있는 방법이 지원(?)되어 버리기 때문에 제한하는 것 같습니다.
좋은 답변 감사합니다 ...
책까지 찾아서 답변해주시고 정말 감사하고요 좋은 공부가 되었습니다 ...
그럼 오늘 하루 잘 마무리 하시고 열공하세여 ~
몇 판에서 읽은 것인가요?
3판은 제대로 읽었는데 그 이후는 읽어보지 못해서...
책이 개정되면서 점점 표준에 정확해지게 변경이 되는 것으로 보였습니다.
하지만 3판을 읽었을 때 이중 pointer 는 다루지 않았었고, 이런 자세한 내용은 다룰 것 같지는 않은데...
혹시 C 기초플러스가 아닌지요.
하여간 합리적인 선택이네요. 이중간접의 경우 막아버리는 것은.
왠지 C++ 의 암시적 형변환이 떠오르는군요.
4판입니다..
7장 함수-C++의 프로그래밍 모듈 - 함수와 배열 - 포인터와 const 섹션에 나온 내용입니다..
C 기초 플러스에도 이런 내용이 나오는지는 모르겠습니다..
답변이 아니고
답변이 아니고 질문드려서 죄송합니다
c언어에서 다음문장이 실행되나요?
int** sm = smCreate(ROWS, COLS); // 여기는 괜찮은데
linkedList_h *L = createLinkedList_h(); // 이부분에서요
저는 c언어는 변수선언이 끝나기전에 상수로 초기화는 되지만 절대 수행코드(함수나 계산식, 제어문)는 동작
하지 못할줄 알았는데 그게 아닌건가요?
C99
C90에서는 안 되지만 최신 표준인 C99에서는 될 겁니다.
그런데 gcc가 C99를 얼마나 잘 지원하는 지는 잘 모르겠어요.;;
코드를 잘 못 이해하신것 같습니다. ~
linkedList_h *L = createLinkedList_h();
헤더의 정의 부분 입니다...
//
// SinglyLinkedList의 구조체 선언
//
typedef struct listNode { // 노드
int row;
int col;
int value;
struct listNode* link;
}listNode;
typedef struct { // 헤더
listNode* head;
} linkedList_h;
//
// 함수 원형입니다
//
#include
#include "SinglyLinkedList.h"
linkedList_h* createLinkedList_h(void) {
/*
변수 선언
*/
linkedList_h* L;
/*
헤더 노드 메모리할당
*/
if((L = (linkedList_h*)malloc(sizeof(linkedList_h))) == NULL) {
ERROR(MALLOCERR);
exit(1);
}
/*
헤더 노드는 아직 가리키는 링크드리스트가 존재 하지 않으므로 NULL로 초기화
*/
L->head = NULL;
return L;
}
음... 뭔가 해결된거 같긴 한데..
포인터를 상수화 하려면
int ** const
이런식으로 써야 하는거 아닌가요
const int **
의 경우는
int ** 형에 대한 const가 아니라
const int 형에 대한 ** 가 됩니다
그렇기 때문에 int ** 를 const int 에 대한 **로 캐스팅할 수 없는겁니다
원형에서 const int ** sm 부분을
int ** const 로 바꾸면
에러도 없어지고 아마 원하시는대로 포인터의 상수화라는 결실도 거둘수 있을거같은데요.
참고로..
this 포인터의 원형은 다음과 같습니다. (디버거 등으로 살펴볼 수 있습니다)
(type) * const this;
this 포인터가 참조하는 주소가 변할 수는 없으므로 위에서 말한 포인터의 상수화를 취한겁니다.
이게 만약 const (type) * this;
이렇게 되있다면 역시 type의 상수형에 대한 포인터이므로 포인터의 상수화가 아닌겁니다.
정리해서 직관적으로 나타내보면
const int a;
const int *pa = &a; (int형 상수의 포인터)
이거고,
int a;
int * const pa = &a; (int형의 포인터 상수)
이거입니다.
이런것도 있겠죠.
const int a;
const int * const pa = &a; (int형 상수의 포인터 상수)
좋은 지적이십니다.
항상 const가 제일 헷갈리는거같아요.
그래서 typedef를 섞어주는게 코드의 이해를 돕죠.
typedef (int **) int_pp
그리고 코드에선,
const int_pp 해주시면 가독성이 증가하지않을까싶습니다.
그런데 위 코드가 맞는지는 아직 콤파일해보지 않아서...
저도 늘 헤깔렸는데 큰 도움이 되었습니다.
감사합니다.
댓글 달기