(C언어)배열 재할당 관련해서 문제가...

morgana의 이미지

안녕하세요.
추운데 감기는 안걸리셨는지요.
제가 과제로 데드락과 관련하여 코딩하는중 문제가 발생했는데, 해결을 못하겠습니다. OTL...

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
 
struct process * init_p(int);
struct resource * init_r(int);
void input(struct process *, int ,struct resource *, int);
int i_check(char *, char * ,int, int);
int edge(struct process *, struct resource *, char *, char *);
int c_check(struct process *, int ,struct resource *, int);
 
struct process{
	char *name;
	int an,rn;
	struct resource *assmnt;
	struct resource *rqst;
};
 
struct resource{
	char *name;
	int rn;
	struct process *rqst_from;
	struct process *assmnt_to;
};
 
void main(){
	int p_size, r_size, check;
	struct process *prcs;
	struct resource *rss;
 
	printf("'Mutual Exclusion', 'No Preemptive', 종류별 자원의 갯수는 1개라 가정합니다.\n");
 
	printf("몇개의 프로세서를 생성 하시겠습니까?: ");
	scanf("%d",&p_size);
	printf("몇개의 자원을 생성 하시겠습니까?: ");
	scanf("%d",&r_size);
	getchar();
 
	prcs=init_p(p_size);
	rss=init_r(r_size);
	printf("p의크기%d r의크기%d\n",sizeof(struct process),sizeof(struct resource));
 
	printf("prcs주소: %d, rss주소: %d\n",prcs,rss);
	//디버깅.
 
	input(prcs, p_size, rss, r_size);
	check=c_check(prcs, p_size, rss, r_size);
 
	if(check==0)
		printf("교착 상태입니다.\n");
	else
		printf("교착 상태가 아닙니다.\n");
 
	free(prcs);
	free(rss);
}
 
int c_check(struct process *prcs, int p_size, struct resource *rss, int r_size){
	void *head;
	int i;
 
	for(head=prcs,i=0; i<p_size; i++){
		printf("p+%d->an=%d\n",i,((struct process *)head+i)->an);
		printf("p+%d->rn=%d\n\n",i,((struct process *)head+i)->rn);
	}
 
	for(head=rss,i=0; i<r_size; i++){
		printf("r+%d->rn=%d\n",i,((struct resource *)head+i)->rn);
	}//디버깅.
 
	/*2개의 구조체를 어떻게 순회 하여 사이클을 찾아볼까나?
	1.홀짝? 2.sizeof를이용? 
	3.간선을 배열에 저장?(문자열배열(2차원포인터) 동적할당?)*/
 
	/*사이클(cycle) : 같은 정점을 두 번 이상 포함하는 경로.
	방향성 그래프에서 경로의 한 에지가 어떤 정점에서 나오고 다른 에지가 
	그 정점으로 들어가면 그 경로는 사이클이다.*/
	/*for(head=prcs,i=0; i<p_size; i++){
		if(((struct process *)head+i)->an!=0 && ((struct process *)head+i)->rn==0){
			return 1;
		}
	}*/
	return 0;
}
 
int i_check(char *text1, char *text2, int p_size, int r_size){
	int temp;
	if(text1[0]!='p' && (text1[0]!='r') || text2[0]!='p' && (text2[0]!='r')){
		printf("잘못입력하셨습니다.  정확하게 입력하세요.\n");
		return 1;
	}
	else if(text1[0]==text2[0]){
		printf("양쪽에 같은 종류가 들어왔습니다..\n");
		return 1;
	}
	else if(text1[0]=='p' && (temp=atoi(text1+1))>=p_size){
		printf("프로세스의 범위를 잘못 입력.\n");
		return 1;
	}
	else if(text1[0]=='r' && (temp=atoi(text1+1))>=r_size){
		printf("자원의 범위를 잘못 입력.\n");
		return 1;
	}
	else if(text2[0]=='p' && (temp=atoi(text2+1))>=p_size){
		printf("프로세스의 범위를 잘못 입력...\n");
		return 1;
	}
 
	else if(text2[0]=='r' && (temp=atoi(text2+1))>=r_size){
		printf("자원의 범위를 잘못 입력...\n");
		return 1;
	}
	return 0;
}
 
int edge(struct process *prcs,struct resource *rss, char *text1, char *text2){
	int temp1,temp2,temp3,temp4;
 
	temp1=atoi(text1+1);
	temp2=atoi(text2+1);
	if(text1[0]=='p'){
		temp3=(prcs+temp1)->rn;
		temp4=rss[temp2].rn;
		if(prcs[temp1].rn==0){
			prcs[temp1].rqst=(struct resource *)malloc(sizeof(struct resource));
			prcs[temp1].rqst=rss+temp2;
 
			printf("prcs.rqst=%d, rss.rqst=%d\n",prcs[temp1].rn,rss[temp2].rn);
			//디버깅.
 
			if(rss[temp2].rn==0){
				rss[temp2].rqst_from=(struct process *)malloc(sizeof(struct process)*(rss[temp2].rn+1));
				rss[temp2].rqst_from=prcs+temp1;
			}
			else{//오류?
				rss[temp2].rqst_from=(struct process *)realloc(rss[temp2].rqst_from, sizeof(struct process)*((prcs+temp1)->rn+1));
				rss[temp2].rqst_from[(rss+temp2)->rn]=prcs[temp1];
			}
 
			printf("prcs[%d].rqst[%d]=%d,%d\n", temp1, (prcs+temp1)->rn, (prcs+temp1)->rqst+(prcs[temp1].rn), rss+temp2);
			printf("rss[%d].rqst_from[%d]=%d,%d\n\n", temp2, (rss+temp2)->rn, (rss+temp2)->rqst_from+(rss[temp2].rn), prcs+temp1);
			//디버깅.
			prcs[temp1].rn++;
			rss[temp2].rn++;
		}
		else{
			prcs[temp1].rqst=(struct resource *)realloc(prcs[temp1].rqst, sizeof(struct resource)*((prcs+temp1)->rn+1));
			prcs[temp1].rqst[(prcs+temp1)->rn]=rss[temp2];
 
			printf("prcs.rqst=%d, rss.rqst=%d\n",prcs[temp1].rn,rss[temp2].rn);
			//디버깅.
 
			if((rss+temp2)->rn==0){
				rss[temp2].rqst_from=(struct process *)malloc(sizeof(struct process)*((rss+temp2)->rn+1));
				rss[temp2].rqst_from=prcs+temp1;
			}
			else{//오류?
				rss[temp2].rqst_from=(struct process *)realloc(rss[temp2].rqst_from, sizeof(struct process)*((prcs+temp1)->rn+1));
				rss[temp2].rqst_from[(rss+temp2)->rn]=prcs[temp1];
			}
 
			printf("prcs[%d].rqst[%d]=%d,%d\n", temp1, (prcs+temp1)->rn, (prcs+temp1)->rqst+(prcs[temp1].rn), rss+temp2);
			printf("rss[%d].rqst_from[%d]=%d,%d\n\n", temp2, (rss+temp2)->rn, (rss+temp2)->rqst_from+(rss[temp2].rn), prcs+temp1);
			//디버깅.
			prcs[temp1].rn++;
			rss[temp2].rn++;
		}
	}
 
	else{
		if((rss+temp1)->assmnt_to!=NULL){
			printf("이미 할당된 자원입니다. 다른 자원을 입력하세요.\n");
		}
		else{
			if(prcs[temp2].an==0){
				prcs[temp2].assmnt=(struct resource *)malloc(sizeof(struct resource));
				prcs[temp2].assmnt=rss+temp1;
				printf("prcs[%d].assmnt[%d]=%d,%d\n", temp2, (prcs+temp2)->an, (prcs+temp2)->assmnt+(prcs[temp2].an), rss+temp1);
				//디버깅.
				prcs[temp2].an++;
			}
			else{
				prcs[temp2].assmnt=(struct resource *)realloc(prcs[temp2].assmnt,(sizeof(struct resource)*(prcs[temp2].an+1)));
				prcs[temp2].assmnt[prcs[temp2].an]=rss[temp1];
				printf("prcs[%d].assmnt[%d]=%d,%d\n", temp2, (prcs+temp2)->an, (prcs+temp2)->assmnt+(prcs[temp2].an), rss+temp1);
				//디버깅.
				prcs[temp1].an++;
			}
			(rss+temp1)->assmnt_to=prcs+temp2;
			printf("rss[%d].assmnt=%d,%d\n\n", temp1, (rss+temp1)->assmnt_to, prcs+temp2);
			//디버깅.
			}
	}
return 0;
}
 
void input(struct process *prcs, int p_size, struct resource *rss, int r_size){
	char *text1, *text2, *input;
	int cnt;
 
	printf("프로세스(자원)와 자원(프로세스)의 관계를 설정하세요.\n");
	printf("ex1) r1,p0 는 자원r1이 프로세스p0에 할당되었음을 뜻합니다.\n");
	printf("ex2) p2,r2 는 프로세스p2가 자원r2와 같은 유형의 자원중에 하나를 요청하여 기다리고 있음을 뜻합니다.\n");
	printf("입력도중 종료를 원할시 end를 타이핑 하세요.\n");
 
	text1=(char *)malloc(1);
	text2=(char *)malloc(1);
	input=(char *)malloc(1);
 
	for(cnt=0; printf("입력하세요:\t"); cnt++){
		fgets(input,10,stdin);
		text1=strtok(input,", ");
		text2=strtok(NULL,", ");
 
		if(0==strcmp(input,"end\n")||0==strcmp(input,"END\n")){
			printf("\n입력을 종료합니다.\n");
			return;
		}
		else if(i_check(text1,text2,p_size,r_size)){
			continue;
		}
 
		else{
			if(edge(prcs, rss, text1, text2))
				continue;
		}
	}
	free(text1);
	free(text2);
	free(input);
}
 
struct process * init_p(int p_size){
	struct process *p;
	char str[4]="p";
	char str2[4];
	int i;
	printf("Process\n");
	p=(struct process *)malloc(sizeof(struct process)*p_size);
	for(i=0; i<p_size; i++,memset(str+1,'\0',3)){
		itoa(i,str2,10);
		strcat(str,str2);
		(p+i)->name=(char *)malloc(sizeof(char));
		strcpy((p+i)->name,str);
		(p+i)->assmnt=NULL;
		(p+i)->rqst=NULL;
		(p+i)->an=(p+i)->rn=0;
		printf("%s\n",(p+i)->name);
	}
	printf("Process %d개가 생성 되었습니다.\n\n",p_size);
	return p;
}
 
struct resource * init_r(int r_size){
	struct resource *r;
	char str[4]="r";
	char str2[4];
	int i;
	printf("Resource\n");
	r=(struct resource *)malloc(sizeof(struct resource)*r_size);
	for(i=0; i<r_size; i++,memset(str+1,'\0',3)){
		itoa(i,str2,10);
		strcat(str,str2);
		(r+i)->name=(char *)malloc(sizeof(char));
		strcpy((r+i)->name,str);
		(r+i)->rn=0;
		(r+i)->assmnt_to=NULL;
		(r+i)->rqst_from=NULL;
		printf("%s\n",(r+i)->name);
	}
	printf("Resource %d개가 생성 되었습니다.\n\n",r_size);
	return r;
}

제가 직면한 문제는 이 파일을 실행 시키고 3개의 자원 3개의 프로세서를 생성한다고 입력하고

p1,r0
p1,r2
p1,r1

로 입력을 하면 정상적으로 작동을 하는듯 싶은데,

p1,r0
p1,r1
p1,r2

로 입력을 할시에는 컴퓨터님께서 역으로 저에게 문제를(첨부파일) 제시해주시네요.(리소스 구조체 포인터가 증발해버리더군요.)

배열 재할당과 관련해서 realloc을 찾아보니, 이래저래 애물단지 라는 말씀은 본거 같습니다.
정녕 지속적으로 들어오는 크기에 맞게 배열을 리사이징할 수 없는것입니까?
새로 할당하고 값을 전부 복사한후 이전 메모리를 해제 하는것이 해결책이 될 수 있을까요?

File attachments: 
첨부파일 크기
Image icon morgana.JPG28.69 KB
doldori의 이미지

소스가 길고 불완전하여 자세히 보지는 않았습니다만,
realloc()이 애물단지라는 말은 들어보지 못했는데요.
realloc()이 하는 일이 "새로 할당하고 값을 전부 복사한후 이전 메모리를 해제 하는것"입니다.

sangwoo의 이미지

음.. 관련이 있을지는 모르겠으나 이전부터 궁금하던 것인데요. realloc을 사용할때

var = realloc(var, newsize);


tvar = realloc(var, newsize);
var = tvar;

이 경우 첫번째 방법이 문제가 될 수 있다는 이야기를 들은 적이 있는데, 사실인가요? 저는 항상 후자로 사용하고 있긴 합니다만.

----
Let's shut up and code.

----
Let's shut up and code.

doldori의 이미지

글쎄요. 어떤 문제가 있는지 전혀 모르겠습니다.
혹시 = 피연산자의 평가 순서와 side effect에 관한 것이라면 괜한 걱정입니다.

irondog의 이미지

input()에서 지역변수로 text1, text2, input을 잡으셨던데, 그 쓰임새가 좀 이상하네요.

Quote:

text1=(char *)malloc(1);
text2=(char *)malloc(1);
input=(char *)malloc(1);

1바이트씩 할당 받는것이 왜 필요한지 이해가 안되네요. 하나씩 살펴보면...
Quote:

fgets(input,10,stdin);

이렇게 input에 10바이트까지 입력 받는 것 같은데 이미 input에 할당된 메모리 사이즈를 넘겨 버렸죠?
Quote:

text1=strtok(input,", ");
text2=strtok(NULL,", ");

여기서 text1, text2는 포인터로만 사용하는데 위에서 처럼 동적메모리를 할당 받을 이유가 없어 보이네요.

거기다가 마지막에 text1, text2를 free() 하시는데, 이미 text1과 text2의 값이 변했기 때문에 free()도 오류입니다.
input()이 호출 될때마다 메모리 누수가 발생 하겠네요.

일단 text1, text2은 메모리 할당 할 필요 없이 놔두시고 input은 10글자를 입력 받으시려면 11bytes로 할당 받는게 좋겠네요. 문자열의 마지막 NULL값도 필요 할테니까...

다른 함수들은 아직 보질 않아서 모르겠고... 아무튼 메모리 문제 같습니다. 다시 잘 살펴 보시길...

morgana의 이미지

리턴형에 대해 잊고 있었네요.
답변 감사합니다.
=======================================
아프다...

=======================================
.

morgana의 이미지

바보같은 실수가 있었네요.

답변해주신분들 감사합니다.(_ _)

=======================================
아프다...

=======================================
.

댓글 달기

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