본문 바로가기

Education

[부스트 코딩 뉴비 챌린지 2020] week3_미션01 + 회의내용

반응형

문제 풀이

/*팀원들의 요구로 인해 주석 설명 추가하였음*/
#include <stdio.h>
#include <cs50.h>
#include <stdlib.h> //atoi()
#include <string.h> //strlen()

void printTable(const char* name, const char* score[], int length);
//점수, 학점 테이블을 띄우는 함수
void loop_ft(void);
//사용자의 성적을 입력 받고 학점을 알려주는 함수. '999'를 입력받기 전까지 계속 반복함
int* charToint(const char *array[], const int length);
/*char형으로 된 score[]를 int형으로 바꾼 배열을 출력하는 함수.
사실 처음부터 score[]를 int형 배열로 만들고 printTable없이 띄워줘도 되지만, 
샘플미션에서의 charArrayToIntArray함수를 보고 이렇게 하면 더 편할 것 같아서 그냥 응용해보았음*/
char* calculate( int student_score, int size);
//사용자에게 입력 받은 성적을 학점으로 계산해주는 함수

//아래 3개는 모두 전역변수(사용자 지정 함수에서도 사용하기 위함)
const int length = 9;
const char* score[] = {"95", "90", "85", "80", "75", "70", "65", "60", "0"};
const char* rank[] = {"A+","A","B+","B","C+","C","D+","D","F"};
const int* score_int = NULL;

int main(void){
    printf("학점 프로그램\n");
    printf("종료를 원하면 '999'를 입력\n");

    printf("[학점 테이블]\n");
    printTable("점수", score, length);
    printTable("학점", rank, length);

    loop_ft();
    return 0;
}

void printTable(const char* name, const char* table[], int size){
    printf("%s : ",name);

    for(int i=0; i<size; i++){
        printf("%s\t",table[i]);
    }
    printf("\n");
}

void loop_ft(void){
    int student_score = get_int("성적을 입력하세요 (0 ~ 100) : ");
    
    if(student_score == 999){
        printf("학점 프로그램을 종료합니다.\n");
        exit(1);
    }else if(student_score > 100 || student_score < 0){
        printf("** %i 성적을 올바르게 입력하세요. 범위는 0 ~ 100 입니다.\n", student_score);
        loop_ft();
    }else{
        score_int = charToint(score, length);
        char* grade = calculate(student_score, length);

        printf("학점은 %s 입니다.\n", grade);
        loop_ft();
    }
}

int* charToint(const char* array[], const int size){
    int *result = malloc(sizeof(int)*size);

    for(int i = 0; i < size; i++){
        result[i] = atoi(array[i]);
    }
    return result;
}

char* calculate(int student_score, int size){
    char* grade = malloc(sizeof(char)*strlen(rank[0]));

    for(int i=0; i<size; i++){
        if(student_score >= score_int[i]){
            strcpy(grade,rank[i]);
            break;
        }
    }
    return grade;

/*혹은, 샘플미션에서 작성된 아래 코드로도 작성이 가능하다.
위의 코드도 가능한 이유는, rank[]함수는 포인터이므로 배열 속 각 data는 "주소"를 담고 있기 때문.
따라서 rank[0], rank[1], rank[2], ... 모두 "크기"가 동일하다. */
    // char* grade;

    // for(int i=0; i<size; i++){
    //     if(student_score >= score_int[i]){
    //         grade = malloc(sizeof(char)*strlen(rank[i]));
    //         strcpy(grade,rank[i]);
    //         break;
    //     }
    // }
    // return grade;
}

 

Code Review

3주차 미션 제출 확인했습니다! 수고하셨습니다.

한가지 아쉬운 부분이 있다면, charToint 함수에서의 input과 output이 항상 같으므로 score_int를 loop_ft 안에서 반복적으로 초기화할 필요는 없습니다. 시간이 불필요하게 낭비되기 때문이지요. loop 밖에서 한 번 초기화하는 것으로 충분합니다.

다시 한번 수고하셨다는 말씀을 드리며, 4주차도 파이팅입니다!

 

2020-07-28 팀원 과제회의 Q&A

Q1. for안에 조건준게 어떻게 된건지 잘 이해가 안가요.

printf("점수: ");
for(int i=0; i<sizeof(SCORES)/sizeof(int);i++){
      printf(" %d\t",SCORES[i]);
 }
 printf("\n");
 printf("학점: ");
 for(int i=0; i<sizeof(*GRADES)/sizeof(char)+1;i++){
      printf(" %s\t",GRADES[i]);
 }
 printf("\n");

아래 사이트가 배열 크기 구하는 방법 설명인데 참고하시면 도움이 되실 것 같아요

 

C 언어 코딩 도장: 36.4 배열의 크기 구하기

반복문으로 크기가 10인 배열의 요소를 모두 출력한다면 다음과 같이 만들 수 있겠죠? int numArr[10] = { 11, 22, 33, 44, 55, 66, 77, 88, 99, 110 }; // 요소가 10개 for (int i = 0; i < 10; i++) // 0부터 10까지 반복 { //

dojang.io

 

Q.2 char*은 범위에 속한 모든 문자를 읽는 것이 맞나요?
   -> 이후에도 *가 지속적으로 쓰이는 데, *의 활용법을 모르겠습니다.

char*는 포인터인데 나중에 저희 강의 5단원에서 포인터를 배우면서 문자열을 표현하는 것에 대해서 배우게 될 것 같아요. 현재 배운 내용으로 설명드리자면 C언어에서 string이라는 데이터 형이 없어서 한 문자만을 나타내는 char를 string와 같이 긴 문자열을 표현?하려면 char*로 표현한다고 생각하면 될 것 같아요.

 

Q3. void 함수명(void)는 어떨 때 사용하는 것인가요?
   -> void는 변환값을 문자, 실수, 정수 어떤 것이든 상관없이 산출해내는 것으로 이해 중입니다!

2단원 5) 사용자 정의 함수 강의에서 void 함수명(void)로 이뤄진 함수는 input, output이 없다고 들었던 기억이 있어요. void는 변수가 없다는 뜻으로, 함수에 아무 것도 넣지 않고 아무 결과도 내보내지 않는다는 함수로 알고있습니다.

 

Q4. 함수(A, B, C...)
   -> 괄호 안 값은 무엇을 의미하는 것인가요? for처럼 변수, 조건, 변화식을 의미하는 것인가요?
       ex) void printTable(const char* name, const char* table[], int size)

만약 a함수에서 b함수를 불러온 경우에, a함수에서 지역변수로 사용하던 값을 b함수에서 사용하고 싶은 경우 b(형식 이름, 형식 이름, ...)을 이용하여 a함수의 지역변수를 b함수로 불러와서 가져와 사용할 수 있게 됩니다.
예로들어서 main함수에서 정의한 size라는 변수가 있는데, 그 변수를 printTable함수에서 사용하고 싶은 경우에 printTable(int 변수명)라고 작성한 후 main함수에서 printTable(size)라고 입력하게되면 size변수를 불러와 printTable함수 내에서 사용할 수 있습니다

 

Q5. 함수 조건식 중 ' || '는 or을 의미하는 건가요?

네 ||는 or을 의미합니다

 

Q6. 62행부터 시작되는 calculate 함수가 어떤 방식으로 작동되는 지 알려주실 수 있으신가요?

calculate함수는 샘플미션의 코드와 동일하게 작성하였습니다. score_int[]배열은 순서대로 95, 90, 85, 80, 75, 70, 65, 60, 0 이라는 숫자가 들어가 있습니다. 이와 동일하게 rank[]라는 char 배열에는 A+, A, B+, B, C+, C, D+, D, F라는 문자가 들어가 있습니다.
 calculate함수에서 score_int[]배열을 받을 부분은 score_array[]입니다. for문에서 i가 0부터 배열의 크기만큼 돌게 되므로, score_array[i]는 i=0일 때 95, i=1일 때  90, i=2일 때 85, ... 가 됩니다.
마찬가지로 calculate함수에서 rank[]배열을 받는 부분은 rank_array[]입니다. 위와 동일하게 rank_array[i]는 i=0일때 A+, i=1일 때 A, i=2일 때 B,... 가 될 것입니다.
만약 학생의 점수가 96점이라고 가정해봅시다. 그렇게 되면 student_score=96입니다. i=0부터 for문을 돌게 되므로 i=0일 때를 먼저 봅시다.  i=0일 때 score_array[i]는 95, rank_array[i]는 A+가 됩니다. 따라서 student_score >= score_array[i]는 96 >= 95이므로 if조건을 만족하게 됩니다. 만족하면 grade라는 변수는 rank_array= A+ 라는 문자열의 크기만큼 grade의 크기를 지정해주고(malloc), rank_array[i]=A+의 문자열을 grade문자열에 복사하여(strcpy) grade의 값은 A+이 됩니다. 그 후 break를 이용하여 for문을 빠져나가게 되고 grade=A+값을 return하여  A+라는 문자열을 돌려주게 됩니다. 

 

Q7. 배열에 const(한정자)를 붙이면 다른 함수로 값을 보낼때 못보내지는건가요? ㅠㅠ const를 없애면 값이 넘어가는데 있으면 자꾸 에러 뜨더라구요...

저도 코드 작성하면서 그 부분에서 문제가 있었는데, 함수 괄호 안에도 const를 붙여서 동일한 데이터형으로 작성해야 해당 데이터를 함수로 보낼 수 있더라구요.

 

Q8. 혹시 char* grade=malloc(sizeof(char)*strlen(rank_array[0])); 코드 의미를 여쭤볼 수 있을까요

malloc(sizeof(char)*strlen(rank[i])))
strlen(rank[i]) : rank[i]의 문자열 길이. 예로 들어서 strlen("block")=5
sizeof(char) = char의 크기. 4.
따라서 sizeof(char) * strlen("block") = 4*5 = 20
malloc은 동적 메모리 할당으로, 괄호 안에 입력된 숫자만큼 메모리를 확보합니다. 그래서 위의 예시처럼 malloc(sizeof(char)*strlen("block")의 경우 입력된 20의 크기만큼 동적 배열을 생성하여 grade의 크기를 미리 지정해줍니다.

따라서 grade = malloc(sizeof(char) * strlen(rank[i])))는 rank[i]의 문자열의 크기를 grade의 크기에도 지정해주는 것이 되겠네요.

 

Q9. 여기서 printTable("점수", score, length) 넣으면, 점수: 95 90 85 이렇게 쭉 나오는 이유가 뭔가요?? 스트링 형식(%s)가 앞에 붙어있으니까 95 90 85 80 ... : <- 이렇게 나와야 하는 거 아닌가용??

void printTable(const char* name, const char* table[], int size){
    printf("%s\t: ", name);    
    for(int i=0; i<size, i++){
        printf("%s\t: ", table[i]);
    }
    printf("\n");
}

맨 처음에
printf("%s\t: ", name);
를 작성하여 먼저 %s : 를 출력합니다. 여기서 %s에 들어갈 부분은 name="점수" 이므로 '점수 : '를 출력하게 되겠죠.그 후 아래의 for문을 통해 score속의 95 90 85 80 ...을 순서대로 출력합니다.

 

Q10. 혹시 charToint 함수 부분 작동 방식 한번만 설명해주실 수 있으실까요..

charToint()함수는 입력받은 char형의 array[]를 int형으로 바꾸는 함수입니다.
array[]를 int형으로 바꾼 함수는 int* result에 저장하여 이를 return로 반환하게 됩니다.for문을 사용하여 array[]속 데이터를 하나씩 바꾸기 시작하는데, 이때 <stdlib.h>라는 라이브러리속에 있는 atoi()라는 함수를 사용해요. atoi()는 char to in라는 의미로 문자열을 정수 타입으로 바꾸는 함수입니다. 따라서 atoi(array[i])를 사용하여 array[i]의 문자열을 int형으로 바꾸고 이를 result[i]속에 저장하게 되어요

사실 charToint함수에서 const char* array[]에서 받을 데이터는 전역변수이므로 받지 않아도 되어요.
즉,

int* charToint(const int size){
    int *result = malloc(sizeof(int)*size);    for(int i = 0; i < size; i++){
        result[i] = atoi(score[i]);
    }
    return result;
}


이렇게 작성해도 상관없습니다.
loop_ft()에서 사용할 땐 score_int = charToint(length); 라고 작성하게 되겠지요

 


제티

char* grade=malloc(sizeof(char)*strlen(rank_array[0]));
저 부분도 제가 잘못 생각했던게.. rank_array 속의 문자열 크기들이 모두 동일하다고 생각해서 for문 돌리기 전에 미리 grade 크기를 지정했었는데 생각해보니 A+와 A의 문자열 크기가 다르더라고요ㅠㅠ 그래서 샘플미션과 동일하게
char* calculate(int student_score, int size){
    char* grade = NULL;    for(int i=0; i<size; i++){
        if(student_score >= score_int[i]){
            grade = malloc(sizeof(char)*strlen(rank[i]));
            strcpy(grade,rank[i]);
            break;
        }
    }
    return grade;
}
와 같이 수정했습니다. 

커몽

A+와 A 의 크기가 다른가요??

제가 sizeof로 출력해봤을 때 크기가 8로 같게 나오던데 ㅠㅠ

제티

저는 위와 같이 나오더라고요!

커몽

저는 배열에 있는 걸 출력해봤는데,, 왜 8로 나오는 건지…ㅠㅠ

그래서 sizeof(GRADES)를 해도 72가 나오더라구요..

제티

아 그렇네요.. 포인터를 사용해서 크기가 모두 동일하겠군요ㅠㅠ char*은 문자열의 첫 주소를 가리키므로 grade[]배열 속의 크기는 모두 동일한게 맞습니다.

제가 위에서 짠 코드는 "A+"문자열의 크기를 본 것이므로 위와 같은 결과가 나왔네요.

커몽

아 그럼 A+ 와 A 의 문자열 자체는 3과 2이고 sizeof(GRADES[n번째])은 배열속에는 포인터로 크키가 모두 같게 할당이 되어서 같게 나오는 거군요!

배열의 크기와 문자열의 크기가 다르군요!

제티

네! 커몽님 덕분에 알게 되었어요 감사합니다

포인터를 사용하기 때문에 배열 속에 int, char 어떤 데이터 형식이든 배열의 크기는 모두 동일하겠지요

커몽

저도 헷갈리던 참이었는데 알게 되었네요

커몽님의 말씀을 듣고 스프레드시트에는 다시 원래 코드로 수정했습니다. grade배열 속의 크기는 모두 동일해서 원래 코드로도 가능하네요.
수정 전과 수정 후의 코드는 틀린 게 아니라 두 가지로 작성이 가능하다는 것이므로 둘다 사용 가능합니다.

 

 

2020-07-28 팀원 과제회의2 Q&A

Q1. 어제 'C언어에서 string이라는 데이터 형이 없어서 한 문자만을 나타내는 char를 string와 같이 긴 문자열을 표현?하려면 char*로 표현한다고 생각하면 될 것 같아요.' 라고 해주셨는데, 근데 저희 수업 영상보면 string 쓰던데 그건 뭔가요?

저희 저번시간에 한 질문에 답변주신 내용을 보면

말씀하신 것처럼 data type 중 string이 없어 처음 사용하기에는 불편하기 때문입니다. C가 python에 비해 어렵다고 말하는 것들 중 하나가 바로 포인터인데요, 문자열을 배열로 나타낸 후 포인터를 이용하여 문자열에 접근해야하기 때문입니다. 이 강좌는 프로그래밍의 처음부터 시작하므로 포인터부터 다 배울 수는 없으므로 여러분을 위해 더 쉬운 방법을 사용한 것입니다. cs50에서만 사용할 수 있는 함수인 get_int나 get_string 등도 모두 여러분이 프로그래밍과 친해지기 위해 staff가 만든 것들입니다.

이렇게 답변주신 내용을 참고하시면 될 것 같습니다.

 

Q2. 그럼 원래는 c 에 string이 없는데 #include <string.h> 이것때문에 쓸수 있었던거에요?

cs50.h 덕분에 사용할 수 있습니다.

반응형