4) add
자. 여기서부터는 이제 위에서 설명한 ' 정렬' 을 반영해서 할 건데, 왜 load 함수에서는 저러한 것들을 반영 안했어 ? 왜냐하면, 우리는 파일을 불러올 때, 이미 그 파일이 정렬되었다고 가정하기 때문이다.
당연히 add 할 때는, 우리가 새로운 사람을 추가하는 것이니까,
add 할 사람의 이름과 번호를 buf1, buf2 에 입력받는다.
이제 이 사람을 전에는 그냥 맨 뒤에 추가했는데, 정렬을 반영해서 넣는 것이다.
처음에 i = n - 1;
즉, i 가 맨 마지막 사람을 뜻하는 것이다.
그 다음 strcmp( names[ i ] , buf1 )
i 번째 사람의 이름과, 내가 추가할 사람의 '이름'을 비교하는 것이다.
strcmp( names[ i ] , buf1 )
두 문자열이 같으면 0 을 반환한다.
만일 names[ i ] 가 buf1 보다 크면, ( 첫번째 문자열이, 두번째 문자열보다 더 크면 )
즉, 사전식 순서로 더 뒤쪽에 나오면, 음수를 반환하고
names[ i ]가 buf1보다 작으면
즉, 사전식 순서로 더 앞쪽에 나오면 , 양수를 반환한다.
( 즉, strcmp 는 단순히, 두 문자열이 같냐, 아니냐. 만 보는 것이 아니라, 사전식 순서로 누가 더 앞에 있느냐. 까지 반환해주는 함수이다 )
그러므로 strcmp( names[i], buf1 ) > 0 라는 것은,
names[ i ] 에 위치한 사람이 새로 입력한 사람보다 더 크다.
즉, 사전식 순서에서 더 뒤에 있다.
그렇다면 shift
즉, 한칸 뒤로 옮기는 작업을 진행한다.
names[ i + 1 ] = names[ i ] # i번째 방에 있는 사람을 i+1 번째 방으로 옮기기
numbers[ i + 1] = numbers[ i ] # i번째 방에 있는 번호를 i+1 번째 방으로 옮기기
이러한 일을 언제까지 해야해 ?
2가지 경우
1) 나보다 작은, 즉 , 사전식 순서에서 나보다 앞선 애, 혹은 같은 애가 나오거나
strcmp( names[i], buf1 ) ≤ 0
2) 맨 왼쪽으로 빠져나가버리는 경우, 즉, 모~ 든 기존의 이름보다, 사전식 순서에서 더 앞에 위치 할때 ( ex. 저 위에서 A 가 B ~ P 보다 더 알파벳 순서상 빨라서, 끝문자, 즉, P 부터 비교하기 시작해서, 점차 앞으로 비교를 해가고, 그 결과 B . 즉, 배열의 맨 처음 위치에 있는 글자보다도 앞이어서, B 보다 한칸 더 왼쪽으로 가서 비교가 되는 경우, 즉, 배열 index[ 0 ] 에 위치하는 B 보다 더 왼쪽으로 가버리는 경우 )
i < 0
>> while( i ≥ 0 && strcmp( names[ i ] , buf1 ) > 0 )
자, 이제 비교가 끝났어, 값을 넣어야 돼. 어떻게 ??
names [ i + 1 ] = strdup ( buf1 )
numbers [ i + 1 ] = strdup ( buf2 )
즉,
나보다 작거나 같은 애가 나왔을 때도, 그 애가 i 번째에 위치하고 있으면 i+1 번째에 내가 입력한 값을 넣기
ex. E 를 넣고 싶은데, D 가 i 번째에 위치한다면 E 는 i+1 번째에 넣어진다.
A 를 넣을 때처럼 i가 -1이 되는 값으로 , 내가 입력한 값이 빠지더라도,
i +1 , 즉, index [ 0 ] 에 값을 넣게 되는 것.
이제, 새로운 사람이 1명, 전화번호부에 추가되었으므로,
n++ 를 해주는 것이다.
그 이후, 성공했다는 메시지 출력해주기
5) remove
1번째와 달리, 내가 입력한 값과, 저장되어 있는 값을 찾는 기능은 remove 자체가 아니라, 그 안에 search 라는 별도의 함수를 따로 만들어서 진행한다.
먼저, search ( buf ) > 즉, 우리가 삭제할 사람의 정보를 buf 에 입력받고, 그 사람이 전화번호부에 어디에 있는지를 검색하는 기능을 수행하는데,
그 사람이 전화번호부에 있으면, 그 사람의 위치, 즉, index 를 반환해주고
만약 그 사람이 전화번호부에 존재하지 않으면 -1 을 return 하도록 해준다.
search 가 return 해주는 값이 index 이고, 그것이 -1 이면, 그런 사람은 없다 ! 라고 출력하고 끝내기
그런 이름을 가진 사람이 있다면 ??
첫번째 version에서는, 그 사람의 정보를 삭제하고 그 칸을 빈칸 혹은 공백으로 남겨두는 것이 아니라, 맨 마지막에 있는 사람의 정보를 그 칸에 넣었다
하지만, 여기서는 그렇게 할 수 없다.
왜냐하면 우리는 사람들을 이름의 알파벳 순으로 정렬 유지를 해야하기 때문이다.
그래서 다른 방식을 진행한다.
만일 B C D E F K M P 라면,
E 를 삭제한다고 했을 때,
F ~ P 를 모두 한칸씩 앞으로 옮겨주는 방법 밖에는 없다.
이 일을 하는 것이 바로,
int j = index for ( ; j < n - 1 ; j ++) { names[ j ] = names[ j +1 ]; numbers[ j ] = numbers [ j + 1 ] ; }
이다.
j는 현재 비어있는 자리이다.
j 를 증가시켜 가면서 j + 1 번째의 사람을 j 번째에 넣는 것이다.
왜 j < n 이 아니라
j < n - 1 일까 ??
n -1 까지 가버리면, n 까지 가는데, 애초부터 names [ n ]은 빈칸이다. 값이 없다.
왜냐하면 n 명의 정보를 저장한다면 배열 index 상으로는 n - 1 이 되기 때문이다.
6) find
첫번째와 거의 유사하다
다만, search 를 통해 반환값이 -1 이면, 현재 전화번호부에 그 사람이 없다는 의미이므로, 그대로 종료한다.
만일 존재한다면, 그 전화번호를 출력해준다.
7) Search
최종코드
#include<stdio.h>
#include<string.h>
#define CAPACITY 100
#define BUFFER_SIZE 20
char *names[CAPACITY];
char *numbers[CAPACITY];
int n = 0;
void add();
void find();
void status();
void remove();
void load();
void save();
int search( char *name){
int i ;
for ( i = 0 ; i< n ; i++){
if( strcmp( name, names[i]) == 0 ) {
return i;
}
return -1;
}
}
int main(){
char buffer[BUFFER_SIZE];
while(1){
printf("$ ");
scanf("%s",buffer);
if( strcmp( buffer, "read") == 0)
load();
if( strcmp( buffer, "add") == 0 )
add();
if( strcmp( buffer, "find") == 0 )
find();
if( strcmp( buffer, "status") == 0 )
status();
if( strcmp( buffer, "delete") == 0 )
remove();
if( strcmp( buffer, "save") == 0 )
save();
if( strcmp( buffer, "exit") == 0 )
break;
}
return 0;
}
void add(){
char buf1[BUFFER_SIZE], buf2[BUFFER_SIZE];
scanf("%s", buf1);
scanf("%s", buf2);
int i = n-1;
while( i > 0 && strcmp( names[i], buf1 ) > 0 ) {
// strcmp( names[i] , buf1 ) > 0 의 의미 ??
// names[i]에 위치한 사람이 새로 입력한 사람보다 더 크다
// 즉, 사전식 순서에서 더 뒤에 있다.
names[i+1] = names[i];
numbers[i+1] = numbers[i];
i--;
}
// 만일, 입력한 이름이 알파벳 순서상, 이미 존재하고 있는 애보다 뒤에 있을 때.
names[i +1 ] = strdup(buf1);
numbers[i+1] = strdup(buf2);
}
void find(){
char buf[BUFFER_SIZE];
scanf("%s", buf);
int index = search(buf);
if( index == -1)
printf("No person named '%s' exists\n");
else
printf("%s\n", numbers[index]);
}
void status(){
int i ;
for( i = 0 ; i < n ; i++){
printf("%s %s\n", names[i], numbers[i]);
}
printf("Total %s people\n", n);
}
void remove(){
char buf1[BUFFER_SIZE];
scanf("%s", buf1);
int index = search(buf1);
if( index == -1 ){
printf("No person named '%s' exists\n", buf1);
return ;
}
// if 문을 거치지 않았다는 것은, 찾는 이름이 전화번호부에 있다는 것.
int j = index;
for( ; j < n-1; j++){
names[j] = names[j+1];
numbers[j] = numbers[j+1];
}
// E 를 삭제한다고 했을 때, F ~ P를 모두 한칸씩 앞으로 옮겨주는 방법 !!
// j 에 아예 새로운 값을 입력하기.
}
void load(){
char fileName[BUFFER_SIZE];
char buf1[BUFFER_SIZE];
char buf2[BUFFER_SIZE];
scanf("%s", fileName);
FILE *fp = fopen(fileName, "r");
if( fp == NULL ){
printf("Open failed\n");
return ;
}
while( fscanf(fp, "%s", buf1 ) != EOF ){
fscanf(fp, "%s", buf2);
names[n] = strdup(buf1);
numbers[n] = strdup( buf2);
n++;
}
fclose( fp );
}
void save(){
int i;
char fileName[BUFFER_SIZE];
char tmp[BUFFER_SIZE];
scanf("%s", tmp);
scanf("%s", fileName);
FILE *fp = fopen(fileName, "w");
// 파일에 쓰기 위해, 파일을 열고, 아래와 같이, 이름과 번호를 입력한다.
if( fp == NULL ) {
printf("Open failed\n");
return ;
}
for( i = 0; i < n ; i++){
fprintf(fp, "%s %s\n", names[i], numbers[i]);
}
fclose(fp);
}
int search( char *name){
int i;
for (i = 0 ; i < n ; i++){
if ( strcmp( name, names[i] == 0 )) {
return i;
}
}
return -1;
}
'C_Data Structure_Algorithm > C telephone v2.0' 카테고리의 다른 글
C 전화번호부 v2.0_1) (0) | 2020.02.28 |
---|