포인터에 대해 질문합니다.

BrownBear의 이미지

char* Return_A()
{
 char* Value = "Hi";
 return Value;
}
 
char* Return_B()
{ 
 char Value[3] = "Hi";
 return Value; //경고, 지역 변수를 반환하고 있습니다. : 반환된 값을 사용하려고 할 시, 정상적으로 사용되지 않습니다.
}
 
int main(int argc, char** argv)
{
 volatile char* Value = NULL;
 
 while(true)
 {
  Value = Return_A();
  Sleep(1);
 }
 
 return 0;
}

while문을 통해 Return_A에서 반환되는 주소를 Value에 넣고 있습니다.

근데 어째서 메모리가 "증가" 하지 않는건가요?

Return_B를 보면 지역 변수를 반환하고 있고, 이 반환된 값을 사용하려고 할 시 정상적으로 사용되지 않습니다.
제가 생각하기에는 Return_B는 스택 프레임에 의해서 함수가 시작 될 때 3개의 바이트를 할당받고 함수가 끝나는 시점에 스택 프레임이 정리가 되어 반환하려고 하면 정리된 주소를 반환하려고 하기 때문에 저런 오류가 발생하는것이고

Return_A는 전혀 이해가 되지 않습니다.

스택 프레임이 아닌 메모리의 할당을 통해 데이터를 집어넣고 그 데이터가 들어있는 주소값을 반환하는걸로 보이는데

그렇다면 메모리 할당 함수(malloc, calloc...)처럼 주소를 할당하여 데이터를 넣어줘야 Return_B처럼 지역 변수를 반환하고 있지 않고 정상적으로 작동(정상적으로 작동되는걸 확인했습니다.)을 할것인데

어째서 while문을 통해 Value에 계속 새로운 Return_A가 반환하는 "Hi"의 주소를 반환을 요청했음에도 불구하고 메모리가 증가하지 않는건가요?

(컴파일러에서 최적화 옵션은 전부 껐습니다.)

익명 사용자의 이미지

data 영역에 있는 Hi 가 저장된 곳
0×60000000 Hi₩0

a에서는 다음과 같이..
0xd0000000 0x60000000
그래서 매번 0x60000000 을 받음

b에서는 다음과 같이
0xd0000000 Hi₩0
0xd0000000 을 리턴받음
근데 스택에 쌓으니 항상 0xd0000000 이라는 보장이 없는 것으로 보입니다

mauri의 이미지

char* Value = "Hi";
ㄴ지금 여기서 사용된 "Hi"는 문자열 상수로서 취급되어 데이터 영역에 기록됩니다.
컴파일러는 Hi를 데이터 영역에 작성하고, Value에 "Hi"의 고정된 주소를 가르키도록 대입시켜 줍니다.
만드신 실행파일 메모장이나 헥사 에디터로 열어보시면 어딘가에 "Hi"라는 문자열이 저장된 것을 보실 수 있습니다.

때문에 for문을 수만번 돌려도 고정된 주소값을 받아오기 때문에 메모리 증가가 없는 것입니다.

BrownBear의 이미지

윗분하고 아랫분 덕분에 쉽게 이해가 되었습니다~ 감사합니다.

익명 사용자의 이미지

"Hi"와 같은 토큰은 string literal이라고 하는데, 이는 기본적으로 상수로 간주됩니다.
즉, 엄밀하게 타입을 따지면 const char * 타입이죠.
그러니 가급적이면 const char* Value = "Hi";와 같이 작성하는 편이 좋습니다.
string literal을 char * 취급하다가, 그게 string literal이라는 걸 깜빡하고 변경하려 들면 아래와 같은 일 중 하나가 생길 수 있거든요.

(1) 프로그램이 죽습니다. read-only page 개념이 있는 아키텍처이고 컴파일러가 그걸 잘 활용했다면 그렇습니다. x86에서 리눅스를 쓰고 있다면 "Segmentation fault (core dumped)"를 보게 되는 거죠.
(2) 당장은 아무 문제 없는 것 같아도, 프로그램 어디선가 다른 string literal의 값이 같이 바뀝니다. (두 string literal이 원래 동일한 문자열이었고, 컴파일러가 그 문자열을 메모리에 하나만 올리는 최적화를 한 경우 이렇게 됩니다.)
(3) 정말로 아무 문제 없을 수도 있기는 하죠.

그럼에도 불구하고 char* Value = "Hi";와 같은 코드가 컴파일되는 이유는 역사적인 이유 때문이라는군요. const 키워드가 만들어지기도 전부터 사람들이 string literal을 char * 타입으로 쓰고 있었고, 그 레거시 코드들이 갑자기 컴파일이 안 되면 혼란이 생길 테니까요. 하지만 새로 작성하는 코드에서는 분명하게 const char *로 간주하는 편이 좋습니다.

kukyakya의 이미지

엄밀하게 타입을 따지자면 string listeral의 type은 const char[] 아닌가요? const char*로 decay 될 뿐이죠.

c++에서는 다음과 같이 문자열 상수의 길이를 구하는 함수를 만들 수 있습니다.

#include <iostream>
 
template <std::size_t N>
constexpr std::size_t constexpr_strlen(const char (&)[N])
{
        return N;
}
 
int main()
{
        std::cout << constexpr_strlen("Hello") << std::endl;
        std::cout << constexpr_strlen("Hello world") << std::endl;
}

너무 엄밀하게 따지는것 아닌가 할 수도 있지만 int array[];의 array가 int*가 아닌것처럼, 명확한 표현이 필요하다고 생각합니다.

익명 사용자의 이미지

옳은 지적이십니다. const만 생각하고 쓰다가 실수했군요.
말씀하신대로 "Hi"의 타입을 정말 엄밀하게 쓰면 const char [3]입니다.

C/C++에서 배열 타입은 포인터 타입(그 배열의 첫 원소를 가리키는 포인터)으로 쉽게 decay됩니다만, 그러지 않고 array type을 살려서 쓰는 방법도 있기 때문에 구분이 필요합니다. 멀리 갈 것도 없이, sizeof("Hi") = 3인 것만 봐도...

댓글 달기

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