포인터 공부중입니다. 될꺼같은데, 세그먼트폴트가 납니다. ㅜㅜ; 한번 봐 주세요.

sia79의 이미지

#include<stdio.h>
#include<stdlib.h>
 
int haha( char* test2[] ) ;
 
int main(void)
{
	int i=0;
    char* a;
 
    haha ( a ) ;
 
    for(i; i<3; i++ )
        printf("%s\n", a[i] ) ;
 
    return 0;
}
 
int haha( char* test2[] ) 
{
	printf("<<< haha START >>>\n");
    test2 = (char * ) malloc( sizeof(char *) * 3 ) ;
    test2[0] = (char *) malloc( sizeof(char) * 5 ) ;
    test2[1] = (char *) malloc( sizeof(char) * 5 ) ;
    test2[2] = (char *) malloc( sizeof(char) * 5 ) ;
 
    memcpy( &test2[0] , "AAAA" , 5 ) ;
    memcpy( &test2[1] , "BBBB" , 5 ) ;
    memcpy( &test2[2] , "CCCC" , 5 ) ;
 
   	printf("<<< haha END >>>\n");
    return 0;
}

haha라는 함수에서는 포인터 배열을 완성시켜서 메인에 그 주소를 넘겨줍니다. haha함수에서 문자열은 일단 고정이지만 가변이 될 꺼구요.
메인에서 이 포인터를 이용해서 haha에서 완성된 문자들을 이용(인쇄)하고 차례차례 프리 시켜주려고합니다만.
세그먼트 폴트 에러를 못 잡겠습니다.

test2 = (char * ) malloc( sizeof(char *) * 3 ) ; 가 char* test2[3]; 과 같게 만들려고 한건데... 제대로 된건가요?

또, malloc함수가 지금 haha에 있는데, 그 함수 벗어나서 메인에 가면 사라진다는데, 값 유지 하려면 전역으로 해야하나요?

athxue의 이미지

memcpy( *test2[0] , "AAAA" , 5 ) ; &test2[0]이런식으로 &가 와야하지 않나요?
memcpy( *test2[1] , "BBBB" , 5 ) ;
memcpy( *test2[2] , "CCCC" , 5 ) ;
memcpy( *test2[3] , "DDDD" , 5 ) ;

sia79의 이미지

아... &군요.
지금 형태에서 test2[0]을 역참조해도 주소라고 생각했는데... 이상하네요;

그런데도 여전히... 폴트 ...

익명사용자의 이미지

포인트 초기화를 안 하셨네요.

parkys1의 이미지

#include<stdio.h>
#include<stdlib.h>
#include <string.h>   // 제 visual studio에서는 안되더군요... linux가 아니라 visual studio에서 돌렸습니다.
 
int haha( char* test2[] ) ;  // 원형 변경
// int haha(char *** test2 );
 
int main(void)
{
    int i=0;
    char* a;      // 일차원 포인터가 아니고 2차원 포인터가 되야 합니다.
    // char **a;
 
    haha ( &a ) ;    // 이 부분은 call by reference나 call by pointer가 되어야 합니다. 그래야 출력하는 부분에서 문제 없음
 
    for(i; i<3; i++ )
        printf("%s\n", a[i] ) ;
 
    return 0;
}
 
int haha(char *** test2 )
{
printf("<<< haha START >>>\n");
    test2 = (char * ) malloc( sizeof(char *) * 4 ) ;   // 4개 로 변경
    test2[0] = (char *) malloc( sizeof(char) * 5 ) ;
    test2[1] = (char *) malloc( sizeof(char) * 5 ) ;
    test2[2] = (char *) malloc( sizeof(char) * 5 ) ;
    test2[3] = (char *) malloc( sizeof(char) * 5 ) ;   // 마지막 DDDD 한줄 추가
 
    memcpy( (*test2)[0] , "AAAA" , 5 ) ;
    memcpy( (*test2)[1] , "BBBB" , 5 ) ;
    memcpy( (*test2)[2] , "CCCC" , 5 ) ;
    memcpy( (*test2)[3] , "DDDD" , 5 ) ;
 
  printf("<<< haha END >>>\n");
    return 0;
}

제가 완성한 코드는 다음과 같습니다.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int haha( char*** test2 ) ;
 
int main(void)
{
	int i=0;
    char** a;
 
    haha ( &a ) ;
 
    for(i=0; i<3; i++ )
        printf("%s\n", a[i] ) ;
 
    return 0;
}
 
int haha( char*** test2 ) 
{
	printf("<<< haha START >>>\n");
    *test2 = (char ** ) malloc( sizeof(char *) * 4 ) ;
    (*test2)[0] = (char *) malloc( sizeof(char) * 5 ) ;
    (*test2)[1] = (char *) malloc( sizeof(char) * 5 ) ;
    (*test2)[2] = (char *) malloc( sizeof(char) * 5 ) ;
	(*test2)[3] = (char *) malloc( sizeof(char) * 5 ) ;
 
    memcpy( (*test2)[0] , "AAAA" , 5 ) ;
    memcpy( (*test2)[1] , "BBBB" , 5 ) ;
    memcpy( (*test2)[2] , "CCCC" , 5 ) ;
    memcpy( (*test2)[3] , "DDDD" , 5 ) ;
 
    printf("<<< haha END >>>\n");
    return 0;
}

sia79의 이미지

악. 갑자기 별 세개짜리 보고 놀랐습니다. 제가 만든 것은 정말 엉망이었군요.
어렵네요. 몇가지 더 답변을 받고 싶습니다.
다른 함수에서 선언한 malloc은 꼭 그 함수에서 프리를 시키거나 다른 함수로 연결해서 가지고 가면 나쁜 코드가 되나요?

char* test[4] ; 을 받으려면 char*** test2로 해야하는 것같은데... 한차원씩 증가해서 넘겨야하는것같은데...
뭐랄까 아직도 잘 모르겠어요. 뭔가 이해하려다가 중간에 붕~ 뜬 기분입니다.

보충 설명 ㅜㅜ 좀;;;

아차, 코드 잘 보았고 많이 도움 됐습니다. 고마웠습니다. 부럽네요. ㅜ.ㅜ

익명사용자의 이미지

포인터를 잘못 사용한 게 한 두가지가 아니네요 -_-; 대충 아래와 같이 수정하면 문제는 없을겁니다.

char ** haha( ) // 오류 시 NULL 을 반환 하면 됩니다.
{
char **test2 = (char **) malloc( sizeof(char *) * 3 ); // char * 를 저장하는 주소니 char **
test2[0] = (char *) malloc( sizeof(char) * 5 ) ;
test2[1] = (char *) malloc( sizeof(char) * 5 ) ;
test2[2] = (char *) malloc( sizeof(char) * 5 ) ; // 3개 까지만 추가 할당

// 위 경우를 아래와 같이 한번에 할당 받으셔도 동일합니다.
// char **test2 = (char **) malloc( size(char) * 5 * 3 );

memcpy( &test2[0] , "AAAA" , 5 ) ; // memcpy( test2, "AAAA", 5) 와 동일합니다.
memcpy( &test2[1] , "BBBB" , 5 ) ; // memcpy( test2+5, "BBBB", 5) 와 동일합니다.
memcpy( &test2[2] , "CCCC" , 5 ) ; // memcpy( test2+10, "CCCC", 5) 와 동일합니다.

printf("<<< haha END >>>\n");
return test2; // 만들어진 char ** 주소 반환
}

int main(void)
{
int i=0;
char** a = haha();

for(i; i<3; i++ )
printf("%s\n", a[i] ) ;

// malloc 으로 각각 할당 받았기 때문에 해제도 해주셔야 합니다.
for(i=0; i<3; i++)
free(a[i]);
// 이것 역시 해제 해주셔야 합니다.
free(a);

return 0;
}

기존 코드 문제점 기술하면

1. haha 선언은 char * [] 형의 변수의 값을 참조만 하지 반환할 수 없는 형태 입니다.
** 형을 반환 받고자 한다면 *** 형으로 선언하고 내부에서는 해당 변수의 *argument 로 접근해야 합니다.
인자로 넘겨서 값을 넘겨 받고자 한다면 해당 변수의 주소를 넘겨야합니다.

그래서 주소값을 인자가 아니라 반환값을 사용하도록 함수형을 예에서는 일부 바꿨습니다.

2. malloc 할당 시 사이즈가 3개 이기때문에 [2] 까지만 할당 받아야 합니다.

익명사용자의 이미지

memcpy( &test2[0] , "AAAA" , 5 ) ; // memcpy( test2, "AAAA", 5) 와 동일합니다.
memcpy( &test2[1] , "BBBB" , 5 ) ; // memcpy( test2+5, "BBBB", 5) 와 동일합니다.
memcpy( &test2[2] , "CCCC" , 5 ) ; // memcpy( test2+10, "CCCC", 5) 와 동일합니다.
 
// 위 코드를 아래와 같이 정정합니다. -_-;
 
memcpy( test2[0] , "AAAA" , 5 ) ; // memcpy( test2, "AAAA", 5) 와 동일합니다.
memcpy( test2[1] , "BBBB" , 5 ) ; // memcpy( test2+5, "BBBB", 5) 와 동일합니다.
memcpy( test2[2] , "CCCC" , 5 ) ; // memcpy( test2+10, "CCCC", 5) 와 동일합니다.

익명으로 쓰니 수정을 못하니 불편하군요 ㅋㅋ
윗분도 답변 자세히 쓰셨는데 두가지 참조하시면 되겟네요.

sia79의 이미지

동적으로 할당한 메모리 인데. test2로부터 +,- 연산은 위험한 것이 아닌가요?
동적할당이라 여기저기 빈 메모리를 쓰는 것이 아닌가요?
혹시 순차적으로 malloc을 쓰지않고 다른 녀석과 함께 사용했으면 중간에 다른 변수가 차지하게 되는거 아닌가요?

익명사용자의 이미지

위험 하지 않습니다. C 언어자체가 그렇습니다. 하나의 malloc 호출은 연속된 공간을 할당해 줍니다.

malloc 과 같은 최 하위 api 가 아닌 메모리를 할당받아 관리하는 클래스등이 구현 스펙에 따라 연속적인 공간을 할당받을지 구현 스펙에 제한적인것이지 malloc은 연속 공간을 할당 받습니다.

c의 array 접근 방식도 위와 같습니다. array 이기 때문에 그러합니다.

단, 특별한 경우가 아니면 array에 대해서 +, - 연산을 하지 않는것이 좋겠지요.

sia79의 이미지

아아, 주석 감사합니다. 뭔가 와 닿는 듯합니다. malloc쪽은 별표가 많아서 어려워보여요.
역시 더 공부가 필요하겠지요. 감사해요.

appleinu의 이미지

malloc 함수를 지역함수에서 사용한다고 해서 메모리에서 값이 없어지는게 아니고..
지역함수 안에서 메모리 값이 없어지는게 아니라 그 메모리를 잡고 있는 포인터가 스택에서 사라지는 것으로
알고 있습니다.

고로 char *a에서 haha(a); 로 넘겨 준 것과 같이 인자값으로 넘겨준 포인터를 가지고 할당된 공간에 접근 할 수
있을것 같습니다~

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`

꽤나 솔직해 질 수 있다...
우연을 바라지 않는다면....

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`

꽤나 솔직해 질 수 있다...
우연을 바라지 않는다면....

sia79의 이미지

정보 고맙습니다. 말씀대로 살아있네요.

익명사용자의 이미지

그 함수가 종료되면 할당된 주소를 접근할 수 없습니다.
포인터가 모두 레퍼런스가 되는게 아니라 포인터 자체가 값에의한 참조가 됩니다.

포인터가 참조가 되기위해서는 해당 변수의 주소가 인자로 넘겨져야합니다.

char * 를 전달만 하는게 아니라 다시 반환 받고자 한다면 char ** 여야 합니다.
char * 내에 저장된 char 값만 참조하고 바꾸고자 한다면 char * 만 인자로 넘겨도 됩니다.

인자가 반환될 경우는 위와 같이 해야하지만,
함수자체 반환값으 경우는 그 자체가 반환 값이기 때문에 char *를 반환 받고자 할때
char *를 반환 하면 되는 것이지요.

포인터라는 개념을 확실히 잡아야합니다.

포인터, 레퍼런스, 변수 라는 단어자체에 현혹 되지 말고 그 단어의 의미를 파악하고 계셔야합니다.
lvalue, rvalue 와 같은 용어도 그렇구요.

sia79의 이미지

말씀 고맙습니다.

익명 wrote:

char * 를 전달만 하는게 아니라 다시 반환 받고자 한다면 char ** 여야 합니다.
char * 내에 저장된 char 값만 참조하고 바꾸고자 한다면 char * 만 인자로 넘겨도 됩니다.

인자가 반환될 경우는 위와 같이 해야하지만,
함수자체 반환값으 경우는 그 자체가 반환 값이기 때문에 char *를 반환 받고자 할때
char *를 반환 하면 되는 것이지요.

이부분이 중요한 말 같은데, 말이 좀 어렵군요;;;
어떤걸 말씀하시려는지 어렴풋이 감은 오는데, 아직;;; ^^;;

gamdora의 이미지

함수를 쓸 때 세 가지 정도의 유형이 있다고 하면,

typedef char *type;
type arg1, arg2, arg3, ret_val;
 
f1(arg1);
ret_val = f2(arg2);
f3(&arg3);

정도가 있겠지요.

f1은 arg1의 값을 받기만 하고 고치지 않으므로 원형이 f1(type)이 됩니다.

f2는 arg2의 값을 받아서 처리 결과를 되돌리지만

고치지는 않으므로 원형이 type f2(type)이 됩니다.

그러나 f3은 arg3의 값을 받아서 고칠 수도 있어야 하므로

원형이 f3(type*)이 됩니다.

쉽게 설명해보려고 애 썼는데 쉬운지 잘 모르겠네요.

아흑! T_T

댓글 달기

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