C++ 파일입출력 fgets

익명 사용자의 이미지

#include "stdafx.h"
#include <iostream>
#include <time.h>
#include <stdlib.h>
 
using namespace std;
 
const int black = 0;
const int red = 1;
 
const int N = 10000;
 
struct node
{
	int b;
	char *key;
	struct node *l, *r;
	node(int bb, char *k, struct node*ll, struct node *rr)
	{
		b = bb;
		key = k;
		l = ll;
		r = rr;
	};
};
struct node *head, *z, *gg, *g, *p, *x;
 
void split(char *insert_key);
struct node *rotate(char *insert_key, struct node *y);
 
class Dict
{
public:
	Dict() // 생성자: z와 head 초기화
	{
		z = new node(black, 0, 0, 0);
		z->l = z;
		z->r = z;
		head = new node(black, 0, 0, z);
	}
	char* search(char *search_key);
	void insert(char *v);
};
 
char* Dict::search(char *search_key)
{
	struct node *x = head->r; // 첫번째 노드를 가리킴
	while (x != z) // 비어있는 노드를 만날때까지
	{
		if (x->key == search_key) // 현재 노드와 탐색 키가 같으면
			return x->key; // 현재 노드 반환
 
						   // 현재 키 값보다 탐색 키 값이 작으면 현재 포인터 왼쪽으로, 크면 오른쪽으로 이동
		x = (x->key > search_key) ? x->l : x->r;
	}
 
	return "doesn't exist"; // 탐색 키가 없으면 -1 반환
}
 
void Dict::insert(char *v)
{
	x = head; p = head;	g = head;
 
	while (x != z) // 비어있는 노드를 만날때까지
	{
		gg = g; g = p; p = x;
 
		if ((x->key) && (!strcmp(x->key, v))) // 만약 삽입할 키가 이미 존재한다면 종료
			return;
 
		// 만약 삽입할 키가 현재 키보다 작다면 왼쪽으로, 크면 오른쪽으로 이동
		if (x->key) x = (strcmp(x->key, v) == 1) ? x->l : x->r;
		else		x = x->r;
 
		// 만약 왼쪽과 오른쪽 노드 색이 빨간색이라면 분할
		if (x->l->b && x->r->b) split(v);
	}
 
	x = new node(red, v, z, z); // 새로운 노드 생성
	if (p->key == NULL) p->r = x;	// 최초의 노드일 경우 헤드의 오른쪽에 삽입
	else if (strcmp(p->key, v) == 1) p->l = x; // 맨 오른쪽 노드보다 삽입 키 값이 작으면 삽입 키를 왼쪽에 삽입
	else									  p->r = x; // 맨 오른쪽 노드보다 삽입 키 값이 크면 삽입 키를 오른쪽에 삽입
 
	printf("%s", v);
  	split(v);
	head->r->b = black;
}
 
void split(char *v)
{
	x->b = red; // 만약 왼쪽과 오른쪽 노드 색이 빨간색이라면 분할
	x->l->b = black;
	x->r->b = black;
 
	if (p->b) // 맨 오른쪽 노드가 빨간색이라면
	{
		g->b = red;
		if ( (strcmp(g->key, v) == 1) != (strcmp(p->key, v) == 1) ) // 빨간색 꺾인 노드 회전
			p = rotate(v, g);
		x = rotate(v, gg); // 빨간색 일자 노드 회전
		x->b = black;
	}
}
 
struct node *rotate(char *v, struct node *y)
{
	struct node *gc, *c;
	c = (strcmp(y->key, v) == 1) ? y->l : y->r;
	if (strcmp(c->key, v) == 1)
	{
		gc = c->l;
		c->l = gc->r;
		gc->r = c;
	}
	else
	{
		gc = c->r;
		c->r = gc->l;
		gc->l = c;
	}
	if (strcmp(y->key, v) == 1) y->l = gc;
	else y->r = gc;
	return gc;
}
 
int main()
{
	Dict d; // 객체 생성
	double start_time;
 
	char *insert_key, *search_key, *result; // 문자열 포인터
	insert_key = (char *)malloc(5 * sizeof(char)); // char 5개 크기만큼 동적 메모리 할당
	search_key = (char *)malloc(5 * sizeof(char));
	result = (char *)malloc(5 * sizeof(char));
 
	FILE *fp1 = fopen("dict.txt", "r"); // 읽기 전용으로 키 값 불러옴
	FILE *fp2 = fopen("search_key.txt", "r");
	if (fp1 == NULL || fp2 == NULL)
	{
		cout << "파일 open 실패." << endl;
		return 0;
	}
 
	start_time = clock();
 
	while (!feof(fp1))
	{
		fgets(insert_key, 6, fp1);
		d.insert(insert_key); // key를 트리에 삽입
	}
 
	cout << "레드-블랙 트리의 삽입 시간: " << clock() - start_time << endl;
	start_time = clock();
 
	while (!feof(fp2))
	{
		fgets(search_key, 6, fp2); // 5 문자씩 불러와서 search_key에 저장
		strcpy(result, d.search(search_key)); // search_key 탐색
 
		if (strcmp(result, search_key)) // 탐색 키가 없거나 잘못된 값을 찾으면
		{
			cout << "탐색 오류: " << search_key; // 오류 출력
			return 0;
		}
	}
 
	cout << "레드-블랙 트리의 탐색 시간: " << clock() - start_time << endl;
 
	fclose(fp1);
	fclose(fp2);
	return 0;
}

main의 첫번째 while문 속 fgets에 대한 질문입니다.
디버깅으로 확인해본 결과
첫 루프를 수행하면 첫번째 insert_key가 head->r에 들어가고,
두번째 루프에서 fgets만 수행하고 insert는 하기 전인데도 불구하고 inserted_key가
head->r에 덮어씌워져 첫번째 insert_key가 사라집니다...
아무리 고민하고 디버깅을 해봐도 왜 그런지 이유를 알 수가 없습니다..
txt파일도 함께 첨부합니다. 제발 고수님들 도와주세요..ㅜㅠㅠㅠ

File attachments: 
첨부파일 크기
Plain text icon dict.txt2.18 MB
Plain text icon search_key.txt2.18 MB
 의 이미지

지극히 당연한 현상입니다.

Dict 자료구조 안의 key가 insert_key와 똑같은 포인터가 되잖아요. 즉 같은 메모리를 가리킨다는 말이지요.

insert_key가 가리키는 문자열을 바꿔도 자료구조 안의 값은 그대로 유지되기를 바란다면, 사본을 만들어 저장해야지요.

글쓴이의 이미지

그럼 트리의 사본을 만들어야한다는건가요..?

댓글 달기

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