[질문] C 이중포인터 상수화 ~ ㅡㅡa

cjynim의 이미지

안녕하세요 자료구조를 공부하다 처음으로 이중포인터에서 상수화 할때 이상한 문제가 있다는 것을 알게 되었

습니다. 그런데 왜 이런 에러가 발생하는지 제 지식으로는 알 수 없어 이렇게 질문을 올립니다.

먼저 제가 구현한 프로그램에서 함수의 인자로 이중포인터를 상수화 하여 보호할 필요가 있어서 이중포인터

를 상수화 한 후 인자에 이중포인터를 주었더니 아래와 같은 에러 메시지가 나옵니다.

일단 제가 구현한 함수와 함께 보여드리겠습니다.

#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 *의 인자로 주어도 이상없이 작동하는데 왜 이중 포인터 일때만 이러한 메시지가 나오는지

이해가 가리안네여 ~ 도와주세여 ~!!

winner의 이미지

그런데 const 를 상당히 착실히 하시는군요.

좋은 습관이긴 한데 Java 이상의 추상화 언어할 때 왠지 적응하기 힘들게 하더군요.
허전하달까, 왠지 불안하달까...?

mokyj의 이미지

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를 간접적으로 변경할 수 있는 방법이 지원(?)되어 버리기 때문에 제한하는 것 같습니다.

cjynim의 이미지

책까지 찾아서 답변해주시고 정말 감사하고요 좋은 공부가 되었습니다 ...

그럼 오늘 하루 잘 마무리 하시고 열공하세여 ~

winner의 이미지

3판은 제대로 읽었는데 그 이후는 읽어보지 못해서...
책이 개정되면서 점점 표준에 정확해지게 변경이 되는 것으로 보였습니다.

하지만 3판을 읽었을 때 이중 pointer 는 다루지 않았었고, 이런 자세한 내용은 다룰 것 같지는 않은데...
혹시 C 기초플러스가 아닌지요.

하여간 합리적인 선택이네요. 이중간접의 경우 막아버리는 것은.
왠지 C++ 의 암시적 형변환이 떠오르는군요.

mokyj의 이미지

7장 함수-C++의 프로그래밍 모듈 - 함수와 배열 - 포인터와 const 섹션에 나온 내용입니다..

C 기초 플러스에도 이런 내용이 나오는지는 모르겠습니다..

athxue의 이미지

답변이 아니고 질문드려서 죄송합니다

c언어에서 다음문장이 실행되나요?
int** sm = smCreate(ROWS, COLS); // 여기는 괜찮은데
linkedList_h *L = createLinkedList_h(); // 이부분에서요
저는 c언어는 변수선언이 끝나기전에 상수로 초기화는 되지만 절대 수행코드(함수나 계산식, 제어문)는 동작
하지 못할줄 알았는데 그게 아닌건가요?

gamdora의 이미지

C90에서는 안 되지만 최신 표준인 C99에서는 될 겁니다.

그런데 gcc가 C99를 얼마나 잘 지원하는 지는 잘 모르겠어요.;;

cjynim의 이미지

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;
}

swiri15의 이미지

포인터를 상수화 하려면

int ** const

이런식으로 써야 하는거 아닌가요

const int **

의 경우는

int ** 형에 대한 const가 아니라

const int 형에 대한 ** 가 됩니다

그렇기 때문에 int ** 를 const int 에 대한 **로 캐스팅할 수 없는겁니다

원형에서 const int ** sm 부분을
int ** const 로 바꾸면

에러도 없어지고 아마 원하시는대로 포인터의 상수화라는 결실도 거둘수 있을거같은데요.

swiri15의 이미지

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형 상수의 포인터 상수)

seank76의 이미지

항상 const가 제일 헷갈리는거같아요.
그래서 typedef를 섞어주는게 코드의 이해를 돕죠.

typedef (int **) int_pp

그리고 코드에선,

const int_pp 해주시면 가독성이 증가하지않을까싶습니다.

그런데 위 코드가 맞는지는 아직 콤파일해보지 않아서...

익명 사용자의 이미지

감사합니다.

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.