char *function() 에 리턴변수로 사용할 수 있는 것..?

jenix의 이미지

char *function()
{
     char str[16];
     
      .... 중략 .....

     return str;
}

위의 코드로 사용하면.. printf(">>> %s\n",function()); 했을때 이상한 값이 출력됩니다..;;

그런데.. char str[16]; 을 char *str; 로 사용하고 했을시엔..

제대로 값이 출력되는데 이유가 뭘까요? :oops:

맹고이의 이미지

함수 내부의 변수는 함수가 끝나면 무효해지니까 그런게 아닐까요?

static char[] 를 쓰시던지 malloc()으로 할당해서 써보세요.

jenix의 이미지

음..

저도 그생각은 해보았는데..

그래서 char *retstr; 을 하나 더 선언하고

strncpy(retstr,str,16); 으로 스트링카피를 해주려고 했는데

strncpy 에서 세그폴트 에러가 나네요 @.@

흐메.. 왜그러징 ㅠㅠ

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

jenix의 이미지

윽...-_-.. 지금은 잘 되네요 대체 뭐가 문제였던거지..

답변 감사드립니다.. -_-;;; strncpy 로 해결..!!;;

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

kslee80의 이미지

첫번째의 경우에 function() 이 사용한 스택 영역을
printf() 가 사용하게 되면서 printf() 가 char 배열이 가지고 있는 영역에
다른 로컬 변수로 값을 덮어써서 발생한 것으로 보이는군요.

여기 BBS 에서 검색해 보시면
char * 타입을 리턴하는 함수에 대한 쓰레드가 있으니 참고하세요.
(예전에 본 기억이 있네요)

purewell의 이미지

jenix wrote:
char *function()
{
     char str[16];
     
      .... 중략 .....

     return str;
}

위의 코드로 사용하면.. printf(">>> %s\n",function()); 했을때 이상한 값이 출력됩니다..;;

그런데.. char str[16]; 을 char *str; 로 사용하고 했을시엔..

제대로 값이 출력되는데 이유가 뭘까요? :oops:

일반적으로 char*는 입력 받은 객체나 static 영역객체를 반환할 때 씁니다.

예>

char* inet_ntoa(struct in_addr in);
char *strstr(const char *haystack, const char *needle);

_____________________________
언제나 맑고픈 샘이가...
http://purewell.biz

jenix의 이미지

헛.. static..

그렇다면.. 그냥 문자열을 리턴시켜주려면..

어떤 포인터형을 써야할까요?

사실.. gethostbyname 에서 도메인네임을 입력받아

마지막 ip 만을.. 스트링 ( char *) 로 넘겨주는 함수를

만들었거든요..

휴 그런데.. 그 함수가 어디서는 세그먼트폴트를 일으키고 어디서는 일으키지 않고 그러네요..

도움 부탁드립니다...에고

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

dudungsil의 이미지

char*를 std::string으로 바꾸시고 로컬 포인터를 리턴해버리세요.

이런식이겠죠.

std::string ReturnLocalString ()
{
    char localArray[128];
    ...
    return std::string (localArray);
    // return localArray라도 관계없죠.
}

int main (void)
{
    std::string wow = ReturnLocalString ();
    ....
}

스트링인 경우에는 편하게 쓸수 있는 방법입니다. 대표적인 Return Value Optimize의 예라서 생성자가 두번 호출되는 일도 없고 쓰기도 편해요.

산넘어 산

jenix의 이미지

헉 저건.. C++ 아닌가요..

전 C 로 플밍하고있었는데.. C 에선 어떻게하죠?;;

C 도 상관없나요?;;

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

jenix의 이미지

     12 char *HostToIp(const char *hostname)
     13 {
     14     char *ptr, **pptr;
     15     char str[16];
     16     struct hostent *hptr;
     17     char *retstr;
     18
     19     if( (hptr = gethostbyname(hostname)) == NULL )
     20         herror(hstrerror(h_errno));
     21     /*
     22     for( pptr = hptr->h_aliases; *pptr != NULL; pptr++ )
     23         printf("\talias: %s\n",*pptr);
     24     */
     25
     26     pptr = hptr->h_addr_list;
     27     for( ; *pptr != NULL; pptr++)
     28     {
     29         inet_ntop(hptr->h_addrtype, *pptr, str, 16);
     30         /* printf("\taddress: %s\n",str); */
     31     }
     32     strncpy(retstr,str,16);
     33     return retstr;
     34 }

이런소스입니다.

위의 소스를 .o 로 컴파일하고..

간단하게 만든 b.c

     12 void main(void)
     13 {
     14     printf(">>> %s\n",HostToIp("www.yahoo.com"));
     15 }

에서는 정상작동을합니다만..

제가 만든 다른 .o 에서 호출하려고 하면 위의 소스에서 strncpy 부분에서 세그폴트를 일으킵니다.. 휴..

---------------------------------------------------------------------------
http://jinhyung.org -- 방문해 보세요!! Jenix 의 블로그입니다! :D

dudungsil의 이미지

대상 포인터를 인자로 넘겨주는 방법을 써야죠.

bool (or void) SomeFunc (char* dest) ;

int main (void)
{
    char szIP[24] ;

    if ( !SomeFunc (szIP) )
    {// error}

    ....
}

방법이야 많죠 뭐. 편한 방법을 찾아서 사용하시면 됩니다. 그리고 static을 사용하는 방법은 의외로 많이 사용됩니다.

리눅스쪽은 어떨지 모르겠지만 gethostbyname도 리턴하는 포인터가 static 구조체의 포인터일껄요. 그 포인터가 제대로 쓰이기 전에 다른 쓰레드에서 gethostbyname이 또다시 호출된다면 그 포인터 값은 유효하지 않을겁니다. 세그먼테이션폴트의 원인이 그것일지도 모르죠.

api중 포인터를 리턴해주는 녀석들은 포인터를 받자마자 바로 데이터에 대한 복사본을 만드시는게 안전합니다. 일반적인것이구요 제일 나은건 api의 행동ㅇ=에 대해서 보다 더 정확히 아는것이 겠죠.

산넘어 산

dudungsil의 이미지

strncpy(retstr,str,16);

이건 세그먼트폴트가 당연합니다. retstr은 그냥 char *retstr; 일뿐입니다.
어딘가를 가르킬(pointer의 운명이죠) 준비를 하고 있지만 그게 어딘지 아무도 모르죠.

저 위의 strncpy를 통해서 어딘지 모를 그곳에 str의 내용을 기록하려고 시도한겁니다. 그러니 죽죠.

또 다른 문제도 있습니다. 중간에 보면 for를 이용해서 inet_ntop를 여러번 호출합니다. (NIC이 여럿 있다면 그렇겠죠) 그런데 무조건 한개의 str만을 이용하는군요. 주석처리한 print를 이용해서 출력만 하고 끝날것이라면 관계없지만 그게 아니라 어딘가로 넘겨줄 데이터라면 이런식으로 하시면 안되죠.

그리고 리턴벨류라는 측면에서도 여전히 낙제입니다.

산넘어 산

맹고이의 이미지

제 생각엔...

int HostToIp(const char *hostname, char *buffer, size_t len)

이런식으로 만드는 게 좋을 것 같아요. ^^;

bugiii의 이미지

문자열 (포인터,리퍼런스) 을 함수에서 리턴하는 방법에 함수 내부의 자동 변수의 포인터나 리퍼린스를 리턴하는 것은 많은 분들의 말씀대로 절대 안됩니다.

다음으로 생각할 수 있는 것이 static이 붙은 함수 내부의 정적 변수나 외부 변수인데, 이것은 보통의 경우 잘 동작합니다만, 쓰레드 프로그래밍을 하기 시작하면 재진입 문제 때문에 사용할 수 없게 됩니다.

보통은 여러분들이 제시하신, 출력 배열을 함수 인자로 주고 그 버퍼에 함수의 처리결과를 담는 방법을 많이 사용하고 있습니다.

하지만, 이것이 정 불편하다... 그런데 쓰레드 프로그래밍을 해야한다... 이러면 2가지 정도 선택이 있을 수 있습니다.

하나는 함수 전체를 둘러싸는 mutex로 방어하는 것이구요. (이것도 문제 있는 경우가 있긴 합니다.)

두번째는 리턴하는 포인터를 쓰레드별 저장소를 이용해서 쓰레드마다 하나씩 새로운 메모리를 할당하는 것입니다.

우리가 자주 쓰는 errno 나 c 라이브러리중 몇몇은 두번째 경우를 사용합니다. 또 쓰레드에 사용할 수 있는 함수라고 해서 함수명 뒤에 _r 을 붙힌 버전도 있는데 이것은 출력이나 내부 상태 저장용 버퍼를 바깥쪽에서 제공해주는 형태입니다.

하지만, 이런 저런 것을 따져 볼 때, 출력 버퍼를 제공하는 것이 좋을 것 같습니다. C++라면, 앞의 방법이나 제대로 된 C++ 객체를 리턴 (복사 비용 주의, 최소화 할 수 있습니다) 하거나 새로운 auto_ptr을 을 이용(new 비용 주의)해야 한다고 생각합니다.

댓글 달기

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