포인터 초기화 관련 재질문

news4682의 이미지

저번에 올리긴 했는데 여전히 해결이 안되는군요

#include<stdio.h>
 
int main(void)
{
    int arr[5]={1,2,3,4,5};
    int * ptr = arr;
    int i;
 
    for(i = 0; i < 5; i++)
    {
        ptr = 2;
        ++ptr;
    }
    printf("%d %d %d %d %d \n", arr[0], arr[1], arr[2], arr[3], arr[4]);
 
    return 0;
}

우선, 코드는 위와 같구요. 개발 환경은 우분투 서버를 이용해서 putty를 사용하고 있습니다.
이때 컴파일을 했을 때,

pointer.c:11:7: warning: assignment makes pointer from integer without a cast [enabled by default]

이런 오류가 뜹니다. 도와주세요 :)

klyx의 이미지

지난 질문에 이미 답이 달려있습니다. 제일 처음 답변 단 익명님의 답변을 참고하세요.
더불어서 warning과 error는 다릅니다.

shint의 이미지

//
int arr == arr[1]과 같습니다.
int arr[0] 은 arr의 갯수가 없다는 말입니다.
 
//이것은
int arr[5]={1,2,3,4,5};
 
//이와 같습니다.
int arr0 = 1;    //arr[1];
int arr1 = 2;    //arr[2];
int arr2 = 3;    //arr[3];
int arr3 = 4;    //arr[4];
int arr4 = 5;    //arr[5];
 
//뭔가 하나가 부족하죠?
int arr5 = 6;    //arr[6]; <-- 6으로 해야 합니다.
 
 
//이것은
int * ptr = arr;
int * ptr = &arr[0]; 과 같습니다.
 
*ptr 은 값'
ptr 은 arr의 주소와 같습니다.

----------------------------------------------------------------------------
젊음'은 모든것을 가능하게 만든다.

매일 1억명이 사용하는 프로그램을 함께 만들어보고 싶습니다.
정규 근로 시간을 지키는. 야근 없는 회사와 거래합니다.

각 분야별. 좋은 책'이나 사이트' 블로그' 링크 소개 받습니다. shintx@naver.com

qiiiiiiiip의 이미지

1. error가 아니라 warning입니다.
1. 메세지를 읽고 이해해 보세요(최소한 노력해보세요) 메세지에 다 있습니다.
1. putty를 사용하고 있다는건 전혀 무관한 이야기이고요
1. 어떻게 컴파일했는지, 실행시켰는지, 실행결과는 어떻게나오는지, 의도는 뭐였는지, 뭐가 문제인지, 제대로된 질문을 하세요.

아마도 원하는 답은 ptr = 2 --> *ptr = 2 일듯.

bushi의 이미지

ptr = 2;
라고 써 놓으셨는데,

2 가 address 라면 ptr 의 type 으로 cast 하시고,

2 가 value 인데 *ptr 의 type 이 int 가 아니라면 *ptr 의 type 으로 cast 해야하고,
ptr 이 아니라 *ptr 에 넣어야 합니다.

takabi의 이미지

*ptr = 2;
또는
* ptr = 2 + i;
등의 의도로 짜신거 아니신지요?

포인터를 이용해서 배열의 값을 바꾸려고 하신듯한데요.

-----

익명 사용자의 이미지

학생이라면 수업을 들으세요,
질문 내용을 보니 기초가 현저하게 부족한거 같은데,
이 상화에서 책만 보고 어찌어찌 하다가 잘못된 길로 빠질거 같네요

익명 사용자의 이미지

xylosper님이 언급하신 질문자님의 저번 글에 첫번째 댓글을 단 사람입니다.

int * ptr = arr;
는 int *타입의 ptr이라는 변수에 arr이라는 identifier가 가진 value(r-value)를 집어넣으신 겁니다.

하지만 arr은 const int *타입입니다. (배열의 identifier이기 때문입니다.)
질문자님은 int *타입의 변수에 const int *타입의 값을 넣으려 했기 때문에 gcc에서 경고를 찍어준 겁니다.

KLDP에서 이렇게 실망스러운 답변이 여러 개 달리는 걸 본적이 없는데 아무도 언급하시는 분이 없네요.
다들 바쁘셔서 질문을 제대로 읽지 못하셨나 보구나 라고 긍정적으로 생각해 보려고 해도 KLDP가 윗 분들처럼 대충 읽고 답변을 달 정도로 건성이 넘치는 커뮤니티였나 싶습니다.

반대로 아예 모르셔서 저런 댓글을 다셨다. 라고 생각해보아도 KLDP가 이렇게 포인터에 대한 기본적인 연산도 모르시는 분들이 많은 곳이었나 싶네요. ㅠㅠ

gilgil의 이미지

> 하지만 arr은 const int *타입입니다. (배열의 identifier이기 때문입니다.)
> 질문자님은 int *타입의 변수에 const int *타입의 값을 넣으려 했기 때문에 gcc에서 경고를 찍어준 겁니다.

처음 듣는 얘기네요.

int arr[5] = {1,2,3,4,5};

라고 했을 때, arr 이 const int 포인터 타입이라는 말씀이신가요?
익명 사용자의 이미지

포인터는 포인터이고, 배열은 배열입니다.
하지만 포인터를 통해 배열을 다룰 수 있습니다.
질문자 님은 포인터를 통해 배열을 다루는 과정에서 생긴 경고에 대해 질문하신 겁니다.

#include <stdio.h>
 
int
main (void)
{
        int arr[5] = {1, 2, 3, 4, 5};
 
        printf ("%d\n", 3[arr]);
        return 0;
}

이런 코드가 정상 작동한다는 사실 알고 계셨나요?

qiiiiiiiip의 이미지

1. 꾸준히 글쓰실거면 아이디를 붙이고 쓰시는게 좋을 듯
1. 지난번 글의 warning과 이번 글의 warning이 다르다는 사실 알고 계셨나요?
1. .....

kukyakya의 이미지

arr은 const int * 타입보다는 int * const 타입에 가깝죠. arr이 가리키는 곳의 데이터는 변경이 가능합니다.

답변 관련해서는 건성으로 답변을 단 것이 아니라 질문자의 질문 내용이 부실했던 탓이라고 봅니다. 워닝 메시지에 해당 라인이 몇번째인지 확인할 수도 없었고, 그에 따라 위에도 어느 분께서 언급하셨던 것처럼 아예 기초가 부족한 게 아닐까 하는 느낌도 들게 된 것 같습니다.

또한 다음과 같은 코드를 gcc -Wall -Wextra로 컴파일했을 경우 ptr이 사용되지 않았다는 워닝 말고는 질문자가 질문했던 워닝이 발생하지 않습니다.

#include <stdio.h>
 
int main()
{
  int arr[5] = {1,2,3,4,5};
  int *ptr = arr;
  return 0;
}

jick의 이미지

arr은 int를 가리키는 포인터 상수로 생각할 수 있죠. (생각할 수 있다..라는 애매한 표현을 쓴 것은 가끔씩 다르게 동작하는 경우가 있기 때문에...)

굳이 말하자면 역할이 int *const에 가깝습니다. const int *와는 아무 상관없습니다.

익명 사용자의 이미지

int * ptr = arr;

해당 문맥에서 배열 이름인 arr은 그 자신의 첫번째 원소를 가리키는 포인터 주소 값으로 변환됩니다.(정식 규칙이 그렇습니다)
따라서 해당 문맥에서 arr의 타입은 const int * 도 아니고 int * const 도 아니고 정확히 int * 입니다.

위 익명님과 같은 기상천외한 얘기가 나오는건, 아마도 '포인터 상수'라는 정체불명의 괴 개념이 발전해서가 아닌가 싶군요.
그냥 array형 수식의 변환규칙을 외우면(예외가 딱 3개 뿐입니다) 간단할 일인데 왜 요상한 방식으로 돌아가는지 저는 잘 모르겠군요.

그리고 원래 질문에서 경고 메시지가 발생하는 부분은
ptr = 2; 입니다.
gcc는 포인터에 형변환 연산자 없이 직접 정수형 상수로 주소값을 대입하는 행위에 대해 경고 메시지를 출력하지요.
물론 위법인건 아니고, 프로그래머의 실수를 방지하기 위한 경고입니다.
이에 대해서는 위에서 bushi님을 비롯해서 여러 사람이 이미 지적을 했을 텐데요...

qiiiiiiiip의 이미지

arr의 타입은 const int * 도 아니고 int * const 도 아니고 정확히 int * 입니다.

이 자신감은 "익명" 이기 때문에 가능한거겠죠?

아래 인용하신대로 ( 같은분일것으로 추정됩니다. )

"array of type" is converted to an expression with type "pointer to type"  ... is not an lvalue

입니다. 반대로 int* ptr의 ptr은 modifiable lvalue죠.
그래서 ptr = 2가 error 아니라 warning이 나옵니다.
arr = 2 는 에러가 나겠지요

그래서 "arr은 int를 가리키는 포인터 상수로 생각할 수 있죠" 라는 jick님의 말씀이
가장 맞는 것 같습니다만..

마찬가지로 로그인하시고 글쓰시면 좋겠습니다.
그러면 글이 훨씬 더 겸손해졌을텐데요..

익명 사용자의 이미지

남의 글 인용을 참 악의적으로 하시는군요.

arr의 타입은 const int * 도 아니고 int * const 도 아니고 정확히 int * 입니다.

앞에 있는 "해당 문맥에서"는 왜 굳이 잘라내셨는지 궁금하군요. 제가 쓴 원문은 다음과 같습니다.

해당 문맥에서 배열 이름인 arr은 그 자신의 첫번째 원소를 가리키는 포인터 주소 값으로 변환됩니다.(정식 규칙이 그렇습니다) 따라서 해당 문맥에서 arr의 타입은 const int * 도 아니고 int * const 도 아니고 정확히 int * 입니다.

짐작하신대로, 아래의 원문을 인용한 것도 제가 맞고, 위의 설명은 아래의 내용을 가지고 그대로 해석한 것에 지나지 않습니다.

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

해당 문맥에서 arr은 array 타입을 갖는 수식이므로 그 자신의 첫번째 원소를 가리키는 포인터 주소값이 되고, 이 값의 타입은 int * 입니다.

참고로, arr = 2; 가 잘못된 코드인 이유는, 대입연산자의 좌변이 modifiable lvalue가 아니기 때문이 맞습니다.

그러나 위의 변환 규칙을 생각한다면, modifiable lvalue가 아닌 array 타입이기 때문이 아니라 lvalue가 아닌(따라서 modifiable lvalue도 아닌) 포인터 주소값이기 때문이라고 보는게 더 정확하겠지요. 다음의 두 링크를 참조하세요.

https://groups.google.com/d/msg/han.comp.lang.c/K_coeSpvwwg/19jhC8-VjhkJ
https://groups.google.com/d/msg/han.comp.lang.c/3EvoiSuYFsw/yfKBzNf_jeQJ

물론 gcc는 해당 상황에서 경고 메시지를 딱 오해하기 좋게 내뱉긴 합니다. 하지만, int *가 modifiable lvalue가 아니라고 내뱉는 것보다는 gcc처럼 써주는게 더 디버깅하기 쉽기는 하지요.

error: incompatible types when assigning to type 'int[3]' from type 'int'

배열을 포인터 상수라고 설명하는게 좋지 않은 이유는 다음과 같습니다.

1) 원문대로의 설명이 훨씬 더 간단명료하다.
2) sizeof 연산자, & 연산자의 피연산자로 사용될 때처럼 배열이 포인터 상수가 아닌 상황이 존재한다.
3) 포인터상수라는 개념은 arr, &arr, &arr[0] 등에 대한 해석과 타입의 추론을 매우 까다롭게 만든다.

익명 사용자의 이미지

그리고 가만히 보면 님은 비로그인만 보면 어떻게 못해서 안달이던데,
멀쩡히 관리자가 답글 달으라고 비로그인 허용해놓은 사이트에서
일개 회원이 남들한테 단지 비로그인이라고 그렇게 함부로 구는 것도 참...

비로그인한테 뭔가 안좋은 일을 당하셨으면
제발 당사자를 찾아서 둘이 해결하시길 바랍니다.
엉뚱한 사람들 물고 늘어지지 말고.

익명 사용자의 이미지

참고로 C99 표준에 나온 문장을 그대로 인용하면 이렇습니다.

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points to the initial element of the array object and is not an lvalue.

배열은 포인터 상수가 아닙니다. 배열은 그냥 배열입니다. 다만 수식 내에서 그것이 쓰일 때, 자동적으로 변환이 될 뿐입니다.
대체 배열이 포인터 상수란 말은 어디서부터 시작된 걸까요?

paser2의 이미지

ptr을 사용해서 arr의 값을 2로 바꾼 다음에 제대로 변경되었는지 출력해보려고 하시는거 같습니다.
본문 소스 중에서

ptr = 2 => *ptr = 2;

로 바꿔주시면 제대로 실행될겁니다
(윈도 비주얼 스튜디오에서 확인했습니다)

저 오류가 뜨는 것은 형변환 문제라고 보면 되겠네요.
int*는 포인터를 저장해야 되는데 그냥 2라고 해놓으면 2는 보통 상수로 쓰이니까요.

값으로 넣고 싶다면
*ptr = 2
같은 형식으로 해야 되겠고

혹시나 직접 포인터 위치를 넣는다고 한다면
ptr = (int *)2
같은 식으로 해야죠.

오류가 말하는 것 역시 형변환입니다 (without a cast)

포인터 부분에 대해서 공부를 좀 더 해보셔야 될 것 같습니다
책에 있는 예제들 실행해보면서 설명 보면 제대로 이해되실거 같습니다

paser2의 이미지

질문을 할 때는 가급적 코드 전체를 보여주면서 질문하는게 좋습니다.
질문이 상세하지 못하면 답도 제대로 하기 힘듭니다.
코드가 너무 길다면 테스트용으로 문제가 있는 부분만 따로 만들어서 올리거나 해야겠지요
그리고 추가로 "저는 이렇게 생각하는데 생각처럼 잘 되지 않습니다"라고 본인 의견도 추가해주시면 답변하는데 훨씬 도움이 됩니다

모든 질문이 이런 식으로 물어볼 수 있는 것은 아니지만
이런 개념부분에서는 너무 추상적으로 질문을 올리시면 질문자도 답변자도 힘듭니다

그리고 책에 나와있는 소스가 오류가 나는 경우도 있습니다.
경우는 보통 2가지로 볼 수 있는데
의도적인 버그의 경우라면 책을 계속 읽으면 자연스레 해결될겁니다
가끔 오타 등으로 생기는 경우도 있긴 한데 출판사나 저자가 그 부분에 대해서 언급하게 마련이니 소스 받을겸 한번쯤 출판사나 저자 홈페이지 들르는 것도 좋습니다
대부분은 전자가 많고 후자는 잘 안 보이긴 했습니다
본문에 오타가 날지언정 소스에 오타는 그리 잘 보이지 않더군요

마지막으로
오류가 떴을때 그 오류를 구글에서 검색만 해도 비슷한 내용의 게시물이 쭈루룩 나옵니다
영어 페이지가 대부분이라 영어에 약하면 힘들수도 있습니다만, 웹번역기를 사용하면 어느정도 알아들을 수는 있지요

두 게시물에 올라온 오류 내용을 검색했다면 보다 빨리 답을 구할 수도 있지 않을까 싶습니다.

minspapa의 이미지

의도하신 것이 어찌되었든, 포인터 변수는 항상 주소만 저장한다 라는 사실만 기억하시고,

임의의 주소를 사용자가 포인터 변수에 넣는 것은 굉장히 위험한 일이라는 것을 기억하시고,

정말 필요할 경우에는, 위의 분들 말처럼, 주소의 앞에 캐스팅을 해주어야합니다. 포인터 변수의 선언에 사용되는 타입은 그 포인터 변수에 저장될 주소의 데이터의 자료형을 의미하기 때문이죠.

익명 사용자의 이미지

질문자께서 한가지 아셔야 하는 것은 경고문에서 11은 11번째 줄을 가리킵니다.

pointer.c:11:7: warning: assignment makes pointer from integer without a cast [enabled by default]

그러니 11번째 줄이 뭔가 틀린게 있나 먼저 보셨어야 하구요, 틀린게 뭔지 잘 모르겠어서 질문을 올리려면 적어도 저 11번째 줄은 포함해야 합니다.

댓글 달기

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