프로그래밍

 3198, 1/160 회원가입  로그인  
   영원한공부
   [C언어] 열혈강의 C 마지막 문제 질문이요.

http://www.hackerschool.org/HS_Boards/zboard.php?AllArticle=true&no=3055 [복사]


열혈강의 도전 프로그래밍 의 마지막 문제 [전화번호 관리 프로그램] 를 작성후 문제가 생겨서요.

구조체포인터 man을 선언후 동적할당으로 구조체 배열을 만든 후에 입력값이 늘어날 때마다 realloc로
재할당하는 방식으로 짰는데요.

** 2개까지는 잘 들어가는데 3번째 입력한 후에(재할당된 후)  1번째, 2번째 입력한 값까지 이상해집니다. **

밑에 있는건 제가 작성한 입력함수입니다.

/* BasicDef.h 에 정의 돼있습니다.  */
typedef struct information
{
     char name[20];
     char Tel[20];
     int use;           //use=1 -> 사용됨 , use!=1 -> 사용 안 됨
} Inform;



/* main함수에 정의 돼있습니다.  */
   Inform * man = (Inform *)calloc( sizeof(Inform), size);





/*  Insert.c  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "BasicDef.h" //구조체 정의, ClearBuffer & ClearScreen 함수 선언

extern int size;   //main함수에 선언된 전역변수. 구조체의 갯수를 저장 (초기값 3)

void Insert(Inform * man)
{
     int i=0; // 구조체 배열에 사용될 변수
                
     while (man[i].use == 1) // use가 1이면 이미 사용 됐다는 뜻.
          i++;           // 다음 구조체를 가리킨다.
        
     puts("[ INSERT ]");
     fputs("Input Name: ", stdout);
     fgets(man[i].name, sizeof( man[i].name ), stdin);
     man[i].name[ strlen( man[i].name )-1 ]='\0'; //끝에 있는 '\n' 지움

     fputs("Input Tel Number: ", stdout);
     fgets(man[i].Tel, sizeof( man[i].Tel ), stdin);
     man[i].Tel[ strlen( man[i].Tel )-1 ]='\0'; //끝에 있는 '\n' 지움

     man[i].use=1; //사용 됐다는 표시
        
     if ( (i+1) == size ) //할당된 구조체를 모두 사용하면 새로 할당
          man=(Inform *)realloc( man, sizeof(Inform) * (size+=3) );

     for(i=0; i<size; i++)   //결과 확인을 위해서 임시로 넣은 것. 문제 해결 되면 삭제할 예정
     {
          printf("[%d번째 구조체] \n", i+1);
          printf("Name : %s \n", man[i].name);
          printf("Tel     : %s \n", man[i].Tel);
     }
        
     puts("\t\tData Inserted");

     ClearScreen();  //정보를 입력 받고 엔터를 한번 더 누른 뒤에 화면을 초기화 시키려고 만든 함수
}



/* 입력함수 실행화면 */


/*  첫 번째  */
[ INSERT ]
Input Name : 1
Input Tel Number : 123
[1번째 구조체]
Name : 1
Tel     : 123
[2번째 구조체]


[3번째 구조체]

                      Data Inserted
/*  두 번째  */
[ INSERT ]
Input Name : 2
Input Tel Number : 456
[1번째 구조체]
Name : 1
Tel     : 123
[2번째 구조체]
Name : 2
Tel     : 456
[3번째 구조체]

                      Data Inserted
/*  세 번째  */
[ INSERT ]
Input Name : 3
Input Tel Number : 789
[1번째 구조체]
Name : 1
Tel     : 123
[2번째 구조체]
Name : 2
Tel     : 456
[3번째 구조체]
Name : 3
Tel     : 789
[4번째 구조체]
Name : 쓰레기값
Tel     : 쓰레기값
[5번째 구조체]
Name : 쓰레기값
Tel     : 쓰레기값
[6번째 구조체]
Name : 쓰레기값
Tel     : 쓰레기값


                      Data Inserted

/*  네 번째  */   여기서부터 이상해요.
[ INSERT ]
Input Name : 5
Input Tel Number : 555
[1번째 구조체]
Name : 5
Tel     : 555
[2번째 구조체]
Name : a
Tel     : 쓰레기
[3번째 구조체]
Name : 쓰레기
Tel     : 쓰레기
[4번째 구조체]
Name : 쓰레기값
Tel     : 쓰레기값
[5번째 구조체]
Name : __COMPAT_LAYER=EnableNXShowUI (쓰레기값인듯)
Tel     : eNXShowUI (쓰레기값인 것 같아요)
[6번째 구조체]
Name : A (쓰레기)
Tel     : ↕ (쓰레기)

                      Data Inserted

그리고

4번째 입력한 후에  man[i].use의 값들은

man[0].use=1
man[1].use=쓰레기
man[2].use=1
man[3].use=쓰레기
man[4].use=81
man[5].use=쓰레기

이렇게 변해있네요. (3번째 입력까지는 정상)


정확한 문제를 모르겠어요.  realloc 문제라면 재할당 해서 새 주소로 값을 복사할 때 문제가 생긴 것 같은데

잘 모르겠네요.












  Hit : 7771     Date : 2011/06/13 04:45



    
profreez realloc 하신다음에
새로 할당된 공간를 초기화 해주세요.

man[새로 할당된 공간].use = 0; // 이걸넣어야 겠죠..
2011/06/13  
영원한공부 profreez// 그렇게 해도 달라지는게 없네요... 문제가 되는게 4번째 입력 후에 건드리지 않은
     1, 2 ,3 번째 데이터까지 변형이 생기는 거인데 이건 해결이 안 되네요
2011/06/14  
prosthetics 이 코드에서 볼 수 있는 오류는 포인터 매개변수네요.

<1 : realloc>
http://blog.naver.com/neutrino37?Redirect=Log&logNo=110005927328
위 사이트에 가보시면 realloc에 대해 자세히 설명이 나와있습니다.
요약하면, 보통 확장할때(realloc)는 위치가 바뀐다고 합니다.
즉, 재할당한 메모리 주소가 이전 메모리 주소랑 다르다는...
->man=(Inform *)realloc( man, sizeof(Inform) * (size+=3) );
->man의 본래의 값이 realloc이 반환한 주소로 바뀜.

<2: 매개변수>
Prototype : insert(Inform * man), 호출(main) : insert(man);
->메인의 man이 가리키는 주소가 insert함수의 man으로 이동
->insert함수 내에서 어떤짓을 해도 main의 man의 값은 바뀌지 않음

<3: 결론>

<1>에서 말한것처럼 realloc은 메모리를 더 큰 것으로 바꿔줍니다.
이 과정에서 월래 있던 메모리가 free될것으로 예상됩니다. (제 생각에는요.)
그리고 insert의 man값은 확장된 새로운 주소를 가리키게 되곘지요.
하지만 <2>에서 말한 대로 main의 man값은 free된(아마) 주소를 가리키고 있을 것이고
insert함수의 man은 함수가 종료되면서 증발되겠지요.
따라서,
main의 man -> 쓰레기 주소 가리킴
inset의 man -> 확장할 때 제대로된 주소 가리켯다가 함수 종료하며 증발

<4: 오류해결방법>

매개변수를 insert(Inform ** man)과 같이 고쳐주시고
호출부분에서 insert(&man);
insert함수 내에서 *man = ...realloc(...);

<5: 의견>

저는 연결리스트를 이용하기 때문에 realloc은 자주 사옹해 보지 않은 지라,
<3>에서 free한다는 말은 가정일 뿐입니다.
또한 여기 나온 코드만 보고는 완벽한 답변을 드릴수가 없군요.
풀코드를 주시면 자세한 분석을 해드리겠지만...
2011/06/14  
영원한공부 prosthetics// 완벽한 답변이었어요. 감사합니다. 제가 여려가지 확인해본 결과 Insert함수만의
문제 같아서 이것만 올린거였어요. 포인터 man은 main함수에서 선언된 지역변수이고 님의 설명대로
고쳤더니 제대로 결과 나왔어요 감사합니다.

그리고 이 방법은 제가 처음 생각했던 방법인데 친구가 열결리스트를 알려줘서 연결리스트로 풀었다가 나중에 제가 생각했던 방법으로 다시 풀어봤는데 이렇게 됐네요.
2011/06/14