구조체포인터를 변수로 받아서 구조체의 멤버변수를 바꾸는 함수

ShaYEL의 이미지

멤버변수가 정의되지 않은 빈 구조체를 선언한 다음,

함수를 이용해서 구조체에 멤버를 넣어주고 싶습니다.

제가 짠 코드는 대충 이런식인데요, 함수를 수행한 뒤에도 구조체가 텅 비어있는 상태로 남아있습니다. 어디가 잘못되었는지 대충 짐작은 가는데 어떻게 고쳐야 하는지 모르겠습니다.

struct address
{
	char *member1;
	char *member2;
	char *member3;
	char *member4;
	struct list_elem e;
};
 
void make_structure (..., struct address *person)
{
	char *data[4];
	.
	.
	.
	/*person의 멤버변수가 될 *data[4]의 값을 만듭니다.*/
	.
	.
	.
	person = (struct address *)malloc(sizeof(struct address));
	person->member1 = data[0];
	person->member2 = data[1];
	person->member3 = data[2];
	person->member4 = data[3];
}
 
void main(...)
{
	struct address person;
	.
	.
	.
	make_structure(&person);
	printf("%s",person->member1);	//data[0]의 주소에 있던 문자열 출력을 기대했는데 garbage가 출력됩니다.
	.
	.
	.
}

조언 부탁드립니다. ㅠㅠ

추가로,

person->member1 = data[0];
person->member2 = data[1];
person->member3 = data[2];
person->member4 = data[3];

이 부분을

person = {data[0],data[1],data[2],data[3]};

이렇게 바꾸면 동작하지를 않는데, 그 이유도 좀 부탁드립니다.

jick의 이미지

"여기다가 데이터 좀 넣어줘요" 하고 기껏 person의 주소를 적어서 보냈는데 malloc해서 엉뚱한 주소를 받아서 잘 채워넣고 "다 채웠어요" 하는군요.

(이를테면 "커피 좀 리필해 주세요" 하고 컵을 내밀었더니 옆에 있는 새 컵을 꺼내서 커피를 따르고는 빈 컵을 도로 돌려주는거죠.)

쓰신 것을 보니 malloc을 없애도 제대로 되지는 않을 가능성이 매우 높아보이는데요, C에서 문자열과 포인터를 어떻게 관리하는지 열심히 읽어보시고 한줄 한줄 따라가면서 지금 무슨 변수가 어디를 가리키고 있고 함수가 리턴하는 순간 스택에서 날아가는 변수가 뭐뭐인지 종이에 한번 그려보세요.

ShaYEL의 이미지

제가 C를 야매로 배웠나봅니다;;;

malloc을 지웠을때 make_structure 함수가 끝나면 *data[4]에 저장된 주소값도 같이 날아가버리나요?? *data[4] 선언을 main에서 해줘야 할것같기도 하네요...

chanik의 이미지

/*person의 멤버변수가 될 *data[4]의 값을 만듭니다.*/ 부분이 잘 준비되었다고 가정하면,
malloc() 한 줄만 없애면 잘 동작할 것으로 보입니다.

make_structure()에 넘어온 person 포인터는 main()에서 스택에 이미 할당된 공간을
가리키고 있으므로 다시 malloc() 해줄 필요가 없습니다. 오히려 오류의 원인이 되죠.
지금의 코드는 불필요한 malloc()에 의해 엉뚱한 공간에 작업하고 있고,
덤으로 memory leak도 발생시키고 있습니다.

이 조치 뒤에도 오류가 생기면, 위의 *data[]의 값을 만드는 부분에 문제가 있는 것입니다.
그때는 그 부분을 단순화해서 올려주시면 해결 가능할 것입니다.

--

printf() 부분도 고칠점이 있네요. '->' 대신 '.' 을 쓰셔야 합니다.

printf("%s",person.member1);

--

두 번째 질문하신 assignment 관련 내용은, C에 그런 문법이 없기 때문입니다.
C99 지원이 되는 컴파일러를 쓰신다면, 좀 억지스럽지만 아래와 같이 구조체 전체를 assign하는 형태는 가능합니다.
단, struct list_elem 멤버까지 함께 임의의 값으로 변경되는 것이므로 주의를 요합니다.

struct list_elem e;
*person = (struct address) {data[0],data[1],data[2],data[3], e};

억지스러운 임시변수 e를 만들지 않고, 아래와 같이 하는 것도 가능합니다.
이것 역시 C99에서만 지원되고, Designated initializers라고 부릅니다.
- http://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html
- http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlcpp8l.doc/language/ref/strin.htm

*person = (struct address) {.member1=data[1], .member2=data[1], .member3=data[2], .member4=data[3]};

이 경우에도 struct list_elem 멤버까지 함께 임의의 값으로 변경될 것 같은데
거기까지는 확인해보지 않았습니다.

익명 사용자의 이미지

person에 왜 malloc을 하시려고 생각하셨나요? 그것과 동일한 이유로 member1 에 malloc이 필요합니다.

익명 사용자의 이미지

음 코드를 제대로 안보고 적었네요.

ShaYEL의 이미지

모두 조언 감사드립니다. 제가 malloc을 잘못 이해하고 있었던 것 같네요... 말씀하신대로 malloc을 지우고 몇가지 확인을 해 보았는데요,

void make_structure (..., struct address *person)
{
	char *data[4];
	.
	.
	.
	/*person의 멤버변수가 될 *data[4]의 값을 만듭니다.*/
	.
	.
	.
	person->member1 = data[0];
	person->member2 = data[1];
	person->member3 = data[2];
	person->member4 = data[3];
 
	printf("%s\n",person->member1);
	printf("%s\n",person->member2);
	printf("%s\n",person->member3);
	printf("%s\n",person->member4); //모두 기대한 값이 출력되었습니다.
}
 
void main(...)
{
	struct address person;
	.
	.
	.
	make_structure(&person);
	printf("%s\n",person->member1);
	printf("%s\n",person->member2);
	printf("%s\n",person->member3);
	printf("%s\n",person->member4); // 모두 garbage가 출력되었습니다.
 
	make_structure(&person);        // FILE* 포인터를 이용하는 함수라서, 한번 더 호출하면
                                           그 다음 문자열을 읽어서 새 구조체를 만드는 방식입니다.
	printf("%s\n",person->member1);
	printf("%s\n",person->member2);
	printf("%s\n",person->member3);
	printf("%s\n",person->member4); // member1만 정상 출력되고,
                                           나머지 모두 garbage가 출력되었습니다.
	.
	.
	.
}

make_structure 안에서 data 값을 확인했을때 문제가 없었으니 *data[4] 만드는 부분은 괜찮은 것 같은데... 그렇지 않나요? 어디가 문제일까요 ㅠㅠ

chanik의 이미지

디버깅에 도움을 원하시면 컴파일이 되는 실코드를 올려주십시오.
문제를 일으킬만한 부분을 감춰두고 추리를 하게 만들지 마시고요.

원본을 올리기가 망설여지시면,
민감한 부분 제거하고 문제가 재현되는 짧은 샘플을 만들어 올리시면 되죠.

라스코니의 이미지

make_structure() 함수내에 char *data[4]의 사용에 문제가 있어 보입니다.

char *data[4] 는 make_structure() 함수 내에만 선언된 지역 변수입니다.
이것을

person->member1 = data[0];

로 대입한다고 해도 그 동작은 그 함수내에서만 제대로 됩니다. 그 make_structure() 함수를 벗어난 순간 person->member1 멤버에 저장된 값은 모두 의미없어집니다.

사실 간단한 문제입니다. data[] 를 malloc 로 잡아서 쓰면 해결되는 문제로 보입니다.

댓글 달기

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