이것저것 관심가는 대로.zip

STUDY/boostcourse

[부스트코스] CS50 3강: 배열 강의 정리 (부제: 코칭스터디 3주차)

썸원 2021. 1. 29. 19:00

* boostcourse 카테고리 내의 CS50관련 글은 네이버 부스트코스 [CS50 - 모두를 위한 컴퓨터 과학]을 수강 후 개인적으로 개념을 정리해본 글. 자세한 강의 내용을 확인하고 싶다면 네이버 커넥트재단이 운영하는 boostcourse 사이트에서 상시 무료 수강으로 진행되고 있는 CS50 강의 수강을 추천합니다.

 

모두를 위한 컴퓨터 과학 (CS50 2019)

부스트코스 무료 강의

www.boostcourse.org

“네이버 커넥트재단은 교육을 통해 개인의 지속적인 성장과 발전을 돕고, 원하는 곳 어디든 배움의 기회가 열리는 세상을 만들기 위해 노력합니다. 부스트코스는 커리어 역량을 강화할 수 있도록, 네이버 커넥트재단에서 기획하고 운영하는 실무형 온라인 교육 프로그램입니다.”

>> 부스트코스 홍보까지는 아니고 ㅎ 무료 강의 추천이다ㅎ


2021/01/10 - [boostcourse] - [부스트코스] CS50 코칭스터디 2기 오리엔테이션

2021/01/16 - [boostcourse] - [부스트코스] CS50 1강: 컴퓨팅 사고 강의 정리

2021/01/22 - [boostcourse] - [부스트코스] CS50 2강: C언어 강의 정리 (부제: 코딩 찌질이)


CS50 3강 배열(Arrays)

  1. 컴파일링
  2. 디버깅
  3. 코드의 디자인
  4. 배열
  5. 문자열과 배열
  6. 문자열의 활용
  7. 명령행 인자

 

2021/02/05 - [boostcourse] - [부스트코스] CS50 4강: 알고리즘 강의 정리 (부제: 아직 2주나 혹은 벌써 2주 남은 코칭 스터디)

2021/02/12 - [boostcourse] - [부스트코스] CS50: 초보자는 헷갈리는 C언어 용어 정리

2021/02/14 - [boostcourse] - [부스트코스] CS50 5강: 메모리 강의 정리 (부제: 설연휴 만세)

2021/02/23 - [boostcourse] - [부스트코스] CS50 6강: 자료구조 강의 정리 (부제: CS50 수강 완료!)

2021/03/03 - [boostcourse] - [부스트코스] CS50 코칭스터디 2기 수료 후기

 

1. 컴파일링(Compiling)

컴파일링

지난 강의에서 간단히 이해하고 넘어갔던 컴파일링(ex.clang, make)은, 사실 아래의 4단계를 거쳐서 진행된다.

  1. 전처리(precompile) 
    전처리기에 의해 수행된다. #으로 시작되는 C소스 코드는 전처리기에게 실질적인 컴파일이 이루어지기 전에 무언가를 실행하라고 알려준다. 예를들어 #include는 전처리기에게 다른 파일의 내용을 포함시키라고 알려주는 것이다. 프로그램의 소스 코드에 #include와 같은 줄을 포함하면 전처리기는 새로운 파일을 생성하는데 이 파일은 여전히 C소스 코드 형태이며 stdio.h 파일의 내용이 #include 부분에 포함된다.
  2. 컴파일(compile)
    컴파일러라고 불리는 프로그램은 C코드를 '어셈블리어'라는 저수준 프로그래밍 언어로 컴파일한다. 어셈블리는 C보다 연산의 종류가 훨씬 적지만, 여러 연산들이 함께 사용되면 C에서 할 수 있는 모든 것들을 수행할 수 있다. C코드를 어셈블리 코드로 변환시켜줌으로써 컴파일러는 컴퓨터가 이해할 수 있는 언어와 최대한 가까운 프로그램으로 만들어 주는 것이다. 컴파일이라는 용어는 소스 코드에서 오브젝트 코드로 변환하는 전체 과정을 통틀어 일컫기도 하지만, 구체적으로 전처리한 소스 코드를 어셈블리 코드로 변환시키는 단계를 말하기도 한다.
  3. 어셈블(assemble)
    어셈블리 코드를 오브젝트 코드로 변환시키는 단계다. 컴퓨터의 중앙처리장치가 프로그램을 어떻게 수행해야 하는지 알 수 있는 명령어 형태인 연속된 0과 1들로 바꿔주는 작업이다. 이 변환작업은 어셈블러라는 프로그램이 수행한다. 소스 코드에서 오브젝트 코드로 컴파일 되어야 할 파일이 딱 한 개라면, 컴파일 작업은 여기서 끝난다. 그러나 그 이상일 경우에는 링크 단계가 추가된다.
  4. 링크(link)
    만약 프로그램이 (math.h나 cs50.h와 같은 라이브러를 포함해) 여러 개의 파일로 이루어져 있어 하나의 오브젝트 파일로 합쳐져야 한다면 링크라는 컴파일의 마지막 단계가 필요하다. 링커는 여러 개의 다른 오브젝트 코드 파일을 실행 가능한 하나의 오브젝트 코드 파일로 합쳐준다. 예를 들어, 컴파일을 하는 동안에 CS50라이브러리를 링크하면 오브젝트 코드는 get_int()get_string()같은 함수를 어떻게 실행할지 알 수 있게 된다. 

CS50강의에서 사용된 소스 코드 예시를 통해 과정을 살펴보면 아래와 같다.

전처리 전전처리 후
1. 전처리 전후

라이브러리를 추가하라는 명령이 해당 파일의 실제 코드로 대체된다. clangcs50.h파일에 들어가 해당 코드를 가져온 뒤 hello.c파일에 붙여넣는 방식이라고 한다. stdio.h역시 마찬가지의 방법을 따른다. 예시는 간단히 나타낸것으로 실제로는 위 아래로도 수많은 코드들이 추가되어 있다고 함.

컴파일 전컴파일 후
2. 컴파일 전후

오른쪽의 바뀐 언어를 보면 보다 복잡한 저수준 프로그래밍 언어(어셈블리어)로 바뀐 것을 확인할 수 있다. CPU가 이해할 수 있는 언어에 조금 더 가까워졌다고 할 수 있다. 참고로 수십년 전까지만 해도 사람들은 이런 코드로 프로그래밍을 했다. 자세히 살펴보면 익숙한 단어들이 몇 개 보인다. 

어셈블 전어셈블 후
3.어셈블 전후

어셈블은 실제 0과 1로 이루어진 머신 코드로 바꾸기 위한 과정이다. 이 단계에서 끝나는 경우도 있지만, 여러 개의 파일로 이루어져 있을 경우에는 아래의 한 단계를 더 거친다.

링크 전링크 전후링크 전후
4. 링크 전후

링크는 모든 0과 1을 하나의 큰 파일로 합치는 과정이라고 생각하면 된다. 

 

 

 

2. 디버깅(Debugging) 

  • 버그(bug): 코드에 들어있는 오류. 버그가 있는 프로그램은 실행에 실패하거나 프로그래머가 원하는 방향으로 동작을 하지 않는다.
  • 디버깅(debugging): 코드에 있는 버그를 식별하고 고치는 과정. 
  • 디버거(debugger): 디버깅을 해주는 프로그램

 

2.1 '버그🦟'와 '디버깅'이라는 단어의 유래

그레이스 호퍼(Grace Hopper)라는 유명 컴퓨터 과학자가 수년 전 동료들과 함께 Mark2 시스템을 만들던 중 컴퓨터 작동에 문제를 겪었는데 그 원인을 알고 보니 나방이었음을 나타내며 노트에 '벌레(버그)가 발견된 첫 사례'라고 표현한 데서 시작되었다. 컴퓨터 과학자들 사이에서 전혀 내려오는 최초의 버그라고 한다.

 

2.2 디버깅의 기본

프로그램은 일반적으로 인간보다 훨씬 빠르게 연산을 수행하기 때문에 프로그램을 실행시켜보는 것만으로는 무엇이 잘못됐는지 찾아내기 어렵다. 반면에 디버거는 프로그램을 특정 행에서 멈출 수 있게 해주기 때문에 프로그래머는 멈춰진 그 지점에서 무슨 일이 일어나는지 순차적으로 확인해 보며 문제를 찾아낼 수 있다. 이때 디버거 프로그램이 멈추는 특정 지점 중지점이라고 하는데, 프로그래머가 프로그램을 한번에 한 행씩 실행할 수 있게 해준다. 

 

2.3 CS50의 디버거 help50 (문법적 오류)

디버거디버거

예시의 소스코드는 #include 없이 함수만 입력했기 때문에 컴파일이 되지 않는 버그를 가지고 있다. 오른쪽은 문제점을 어떻게 나타내는지 보기 위해 help50을 통해 다시 코드 컴파일을 실행시킨 모습이다. 일반적인 오류 메시지 뒤에 보다 자세하게 버그가 나타난 이유와 지점에 대해 알려주고 있다. 컴파일조차 되지 않는 단계에서 사용하기 좋은 디버거다.

 

2.4 printf를 통해 버그 살펴보기 (논리적 오류)

논리적 오류논리적오류

위의 예시는 앞선 예시와 달리 코드 컴파일은 문제없이 잘 실행된다.

그런데 애초에 코드를 작성한 목적이 #을 '10개'출력하는 것이라고 가정하면 결과는 11개가 출력되기 때문에 수정이 필요하다. 예시의 경우 짧은 코드이다 보니 사실 printf까지 사용하지 않아도 바로 원인을 파악할 수 있지만, 실제로는 보다 긴 코드들이 많아 문제점을 찾기가 어렵다고 한다. 현직에서 일하시는 분의 말을 따르면 직접 작성한 코드에서 오류를 찾아야하는 바로 그 순간에는 잘 안보이는 경우가 많다고 한다 ㅋㅋ

논리적오류논리적오류
printf() 추가

예시에서는 printf로 출력되는 값 앞에 횟수를 명시적으로 드러냄으로써 오류 원인을 추측할 수 있도록 했다. 0부터 시작했으므로 9에서 끝나야 하는데 10까지 진행되어 총 11개의 #이 출력됐다. 원인을 찾았으니 (int i=0; i<10; i++)로 수정한 뒤에 추가했던 printf()를 지워주면 된다.

 

2.5 CS50 IDE의 debug50 (논리적 오류)

 

CS50 IDE

integrated development environment for students and teachers

ide.cs50.io

IDE
CS50 IDE 접속 화면

CS50 Sandbox의 조금 더 개선된 버전이다. 오른쪽 바에 Debugger가 바로 보이는 것을 확인할 수 있다. 디버거를 클릭하면 아래와 같이 실행관련 창이 열린다.

디버거

문제점을 찾고 싶은 부분의 행 번호를 클릭하면 빨간색으로 표시가 되면서 디버거에 중지점이 추가된다. 앞서 정리했듯, 사용자가 한단계씩 진행하며 문제점을 추측해볼 수 있도록 하는 구간을 미리 지정하는 것이다. 

디버거

debug50 파일이름을 입력한 뒤 실행하면 중지점에서 멈춘 디버거가 현재 위치를 노란색으로 알려준다. 오른쪽 창을 통해서 변수의 값에 대한 부분도 볼 수 있는데, 창 위쪽의 실행버튼 옆의 Step over 버튼을 통해 한 단계씩 진행 가능하다. 실행버튼을 누를 경우 프로그램 끝까지 한 번에 실행해버리기 때문에 디버깅의 의미가 없으므로 play버튼은 문제를 찾은 뒤에 실행하면 된다. 

이런 디버깅 과정은 printf()처럼 어차피 지워버릴 코드를 추가하지 않으면서도 컴퓨터 메모리 안에서 벌어지는 일을 단계적으로 살펴볼 수 있다는 장점이 있다. 문제를 확인한 후 코드를 실행하는 대신 바로 디버깅을 종료하려면 Ctrl+c를 누르면 된다(근데 맥에서는 단축키가 작동하지 않는 것 같다. Command나 Control 모두 무반응).

 

2.6 디버거, GDB (논리적 오류)

GDB는 자주 쓰이는 디버거 중의 하나로, C프로그램에 GDB를 실행시키려면, 먼저 프로그램을 컴파일해야 한다. 그 다음 gdb 소스코드이름을 터미널에 입력 후 실행하면 된다. 

GDB가 실행된 다음에 가장 먼저 해야할 일은 중지점을 설정하는 것이다.

  • 어디에서 프로그램이 잘못되는지 짐작이 갈 경우에는 그 지점 이전에 있는 행에 중지점을 설정해서 생각한 그 지점에 들어섰을 때 어떻게 변하는지 보는 것이 좋다.
  • 어디가 문제인지 확실하지 않다면, 처음부터 모든 코드를 살펴볼 수 있도록 main 함수의 첫 행에 중지점을 설정한다.

중지점을 설정하기 위해서는 프로그램을 멈추고 싶은 행번호 다음에 b(breakpoint)를 입력후 엔터를 누르면 된다. 현재의 모든 중지점을 보고 싶다면 info b를 입력하면 된다. 중지점의 행번호 다음에 clear를 입력하면 중지점을 제거할 수 있다.

Command 명령 Result 결과
b add breakpoint 중지점 추가
r runs program 프로그램 실행
info b shows breakpoint 모든 중지점 보기
clear(#) removes breakpoint 중지점 제거
n step forwoard one block 한 블럭 앞으로 가기
s step forward one line 한 행 앞으로 가기
p [var] print variable value 현재 지점의 프로그램 변수 값 출력하기
info locals print local variable values 현재 모든 지역 변수값 출력하기
bt show function calls
q quit GDB 종료하기
c continue progrm 프로그램 계속 실행하기

 

중지점을 설정했다면, r(run)을 입력하여 GDB를 실행한다. 만약 작성한 프로그램이 명령어 인자를 받는다면 r다음에 인자들을 쓰면 GDB가 실행된다.

GBD가 실행된 다음 중지점마다 프롬프트가 나타나는데, 이때 몇 가지 옵션이 있다.

  1. 현재 지점에서의 프로그램의 변수값을 보고 싶다면 변수 이름 p(print)를 입력하고, 현재 모든 지역의 변수값을 보고 싶다면 info locals를 입력하면 된다. 
  2. 코드의 다음 행으로 나아가고 싶다면 n(next)을 입력하면 된다. s(step)도 다음 행으로 갈 수 있는데, 함수 내부로 들어가서 함수 내부의 각 행을 훑는다.
  3. 프로그램을 계속 실행하고 싶다면 c(continue)를 입력하는데, 이때 중지점이 없다면 프로그램이 종료된다. 만약 중지점이 있다면 계속해서 다음 중지점에서 멈춘다.

 

 

 

 

3. 코드의 디자인

3.1 CS50의 check50 (자동 검사 프로그램)

CS50강의의 과제를 자동으로 채점하기 위해 제작된 프로그램이다. 실제로 많은 사람들이 함께 작업하는 환경에서는 이와 같은 자동 검사 프로그램을 활용하는 것이 많은 도움이 된다고 한다. 여러 사람들이 각자 한 부분을 맡아 코드를 작성할 때 각자가 수정한 코드가 전체 프로그램의 정확성을 해치지 않는지 편리하게 확인해주기 때문.

 

3.2 CS50의 style50 (코드 디자인 검사)

코드를 작성할 때 굳이 엔터를 이용하여 함수 간의 간격을 벌리거나 Tab으로 들여쓰지 않아도 컴퓨터는 코드를 읽어내는 데에 문제가 없다. 그러나 코드를 작성할 때에는 코드를 작성한 본인, 그리고 다른 사람들이 코드를 읽거나 유지∙보수하기 쉽도록 해야한다. 

코드 디자인코드 디자인코드 디자인
코드 디자인의 차이

같은 코드라도 어떻게 디자인하느냐에 따라서 느낌이 전혀 다른 것을 볼 수 있다.

많은 회사들은 보통 사내에서 코드를 작성할 때 불필요한 오해를 없애고 코드를 이해하는 데 드는 비용을 최소화하기 위해 특정한 스타일 가이드를 따르도록 한다. 

코드 디자인
코드 디자인
style50 실행 모습

초록색 하이라이트를 통해 공백을 넣어야 하는 부분을, 빨간색 하이라이트를 통해 지워야하는 부분을 알려주고 있다. 이러한 기능은 코드의 정확성과는 관련이 없지만, 심미적인 부분 또한 중요하게 다뤄야 함을 알려준다. 

 

3.3 고무 오리 디버깅 (rubber duck debugging)

러버덕 디버깅
이미지 출처: Unsplash / rubber duck debugging 이미지가 없어서 🦶합성함. 사용한 이미지는 본문 아래 기재.

코드의 오류를 해결하기 위해 help50(코드의 문법적 오류 검사), debug50(코드의 논리적 오류 검사), check50(자동 검사)과 같은 프로그램을 모두 실행했지만 여전히 원인을 찾지 못했을 경우에는 잠깐의 휴식을 취한 뒤 다시 코드를 돌이켜보는 수밖에 없다. 컴퓨터 과학에서는 '고무 오리 디버깅'이라고 하는데, 코드에 대해 이야기를 나눌 사람이 없다면 책상 위에 작은 고무 오리를 올려 두고 방문을 닫을 뒤 ㅋㅋ 고무 오리에게 코드에 대해 설명해보는 것이다. 친구에게 설명하듯 한줄 한줄 코드를 설명하다 보면 언젠가는 스스로 깨닫게 되는 순간이 오게 되는데 그럼 다시 오리를 내려놓고 ㅋㅋ 코드를 수정하면 된다고 한다.

이 방법은 결국 신중한 사고 과정을 위한 것으로, 문제를 해결하는 데에 있어 도구 의존도를 낮추고 다시 사람에게 집중하게 하는 추가적인 매커니즘이라고 한다. 

러버덕
석촌호수 러버덕이 생각나서 만든 짤

해야되는 강의 정리는 안하고 이미지 만들고 짤 그리는 데에 정성 쏟음(공부 못하는 애들 특징).

 

 

 

4. 배열

4.1 컴퓨터 메모리(RAM)

C에는 아래와 같은 여러 자료형이 있고, 각각의 자료형은 서로 다른 크기의 메모리를 차지한다.

bool 불리언 표현 ex. True, False, 1, 0, yes, no 1byte
char 문자 하나 ex. 'a', 'B', 'y', 'n', '?' 1byte
int 정수 (40억까지) ex. 3, 65, -9, 0 4byte
float 부동 소수점을 갖는 실수 ex. 3.14, 0.0, -65.56 4byte
long (int 보다 큰)정수 더 많은 비트를 사용하여 int보다 더 높은 수를 센다.

* 40억개 이상의 데이터를 가진 일부 거대 기업(페이스북, MS)과 같은 상황이 아닌 일반 사용자들은 대부분 정수에 int를 사용한다.
8byte
(=64bit)
double 부동 소수점을 포함한 더 큰 실수   8byte
string 문자열 쌍따옴표 안에 들어간 한 개 이상의 문자들. 보통 char 하나하나 보다 크다. ~byte

⚠️char 값을 표현할 때에는 '작은 따옴표' 안에 문자를 넣고, string 값을 표현할 때에는 "쌍따옴표"안에 문자열을 넣는다. 

RAM
RAM

컴퓨터나 노트북, 스마트폰 등에 있는 이 검은 칩은 소프트웨어 구동 시 정보가 저장되는 곳으로, 여러 바이트들의 묶음이라고 생각할 수 있다. 만약 컴퓨터의 메모리가 1GB라면, 10억바이트가 될 것이다.

예시의 사진은 컴퓨터에서 메모리의 데이터 처리 방식을 가시적으로 살펴보고 이해하기 위해 메모리 위에 가상의 칸(노란 선)을 나눈 모습이다. 한 칸에 1byte라고 가정했을때, int값 하나를 처리한다고 하면 4칸을 사용하게 되는 것이다.

만약 char을 이용하여 대문자 3글자를 표현하는 함수를 실행했을 경우에는 아래와 같이 메모리를 사용했을 것이다.

charchar
메모리

글자는 아스키(ASCII)코드를 통해 숫자에서 글자로 표현된 것이므로 다시 숫자로 표현해본다면 아래와 같다. 

메모리

이처럼 컴퓨터는 사실상 숫자를 처리하고 있으므로 글자를 숫자로 출력하게 할 수도 있다. 

%i
%c에서 %i로 변경 후 (가독성을 위해 띄어쓰기 했다)
메모리

char값을 %c가 아니라 %i, 즉 정수값으로 표현하도록 했더니 아스키코드에 나온 이진법 값을 십진법으로 변환한 값이 출력되었다.

참고로 반대의 경우도 가능하다고 한다.

 

4.2 배열

시험 점수의 평균값을 구해야할 때, 가장 기본적인 방법은 해당 과목의 점수를 모두 입력하고 더한 뒤 그 수만큼 나누어주는 것이다. 

평균값 구하기
4.2.1 과목 평균값 구하기

그러나 이 방법은 일상에서는 괜찮을지 몰라도, 프로그래밍에서는 적합하지 못하다. 어쩌면 항목이 늘어날 수도 있는 과목의 점수를 매번 입력 + 모든 과목의 수를 알아낸 뒤 다시 그 값으로 나눔 + 수정사항이 생겼을 때에는 매번 직접 수정해주어야하는 등의 번거로움이 있기 때문이다. 

이 때 활용할 수 있는 것이 배열의 개념인데, 배열은 같은 자료형의 데이터를 메모리상에 연이어서 저장하고 이를 하나의 변수로 관리하기 위해 사용한다.

배열 넣기
4.2.2 코드에 배열 넣기

먼저 같은 함수에 배열만 넣은 것이다. 여전히 계산을 하는 방식에는 큰 변화가 없으므로 정리는 되었으나, 좋은 코드는 아니다.

특히 과목이 세개임을 입력하고 다시 그 과목수만큼 나누는 부분은 나중에 다시 코드를 수정해야할 때 버그를 만들어내는 함정과도 같다고 한다. 코드를 작성한 뒤 한참의 시간이 지난 뒤에 다시금 코드를 수정해야 할 때는 과목의 수와 나누는 수가 같아야 한다는 사실이 전혀 와닿지 않기 때문이다. 

변수 지정
4.2.3 과목 수를 변수로 지정

과목수를 지정하지 않고 변수로 만들어 줄 수 있지만, 여전히 코드 안에, 그것도 함수 안에 고정되어 있으므로 번거롭다.

상수 설정
4.2.4 상수 설정

아예 메인 함수에 들어가기 전 상단에 const int N을 입력해서 상수 값을 지정해주면 실수로 그 값을 변경하지 않도록 도와줄 수 있다. N은 변수 이름으로 원하는 대로 작성할 수 있지만, 관습에 따라 대문자 N으로 적는다고 한다. 이를 전역변수라고 하는데, 함수 바깥에서 선언하는 변수를 뜻한다. 변수값에 변동이 생기면 코드를 살펴볼 필요없이 함수 상단에서 수정해주면 되므로 편리하다. 

하지만 여전히 평균값을 구하는 방식은 변함이 없으므로 개선이 필요하다.

배열 및 함수 사용
4.2.5 배열 및 함수 사용

레알진짜최종최종최종.c ㅋㅋㅋㅋㅋ

사용자가 입력한 값(이 경우 전체 과목 개수)에 따라 유동적으로 결과를 출력할 수 있도록 배열을 만들고 그 배열을 이용해서 평균을 구하는 함수를 이용하여 코드를 작성했다. 각 행에 대해 보다 자세히 설명을 하자면 아래와 같다. 

배열 및 함수 사용
4.2.5 배열 및 함수 사용 + 주석

주석 뒤의 숫자는 코드의 흐름에 대한 순서로 읽기 힘들지만 그래도 순서에 따라 코드를 읽어나가면 보다 이해하기 쉽다. 

  • (3) i+1은 점수를 입력받을 때 나타나는 숫자가 1부터 시작할 수 있도록하기 위함이다.
  • (4-1) int length, int arraylengtharray는 변수 이름이므로 원하는 다른 글자로 대체해도 되지만 나중에도 이해하기 쉽도록 지칭하는 값을 그대로 넣는 것이 좋다.
  • (4-2) float average(int length, int array)이기 때문에 return(반환 값)은 정수 /(나누기) 정수가 되어 float함수임에도 정수값이 반환되어버리기 때문에 마지막에 length의 형식 지정자를 (float)으로 바꿔줬다. 이때 분모 분자 모두 float일 필요 없이 어느 하나만 float이어도 출력값은 float이 된다.
  • (5) 함수 프로토 타입 입력후에는 세미콜론(;)을 붙여주는 것을 잊지 말 것.
  • (6-1) 평균 값을 소수점 한자리까지 표현하기 위해 %.1f로 입력하였다. 만약 소수점 두자리 값이 나온다면 끝에서 반올림해서 한자리수로 표현한다.
  • (6-2) float값은 밑의 float average(int length, int array[])함수를 통해 나온 값이므로 ,average(계산하고자 하는 배열의 길이, 계산에 사용된 배열)을 끝에 적어주면 된다. 따라서 ,average(n,scores)가 된 것이다.

배열 및 함수 사용 코드 실행
4.2.5 배열 및 함수 사용 코드 실행 화면

 

 

 

5. 문자열과 배열

5.1 문자열의 의미

문자열(string) 자료형의 데이터는 사실 문자(char) 자료형 데이터들의 배열이다.

string s = “MAP”; 과 같이 문자열 s를 정의한다면 s는 문자의 배열이기 때문에 포스트 위쪽의 '4.1 컴퓨터 메모리'에서 보았던 이미지처럼 메모리 상에 아래 표와 같은 형태로 저장된다. 그러므로 인덱스로 각 문자에 접근할 수 있다.

M A P \0
s[0] s[1] s[2] s[3]

표에서 볼 수 있듯, 문자열 마지막 인덱스는 '널(\0)'로 끝난다. 널 종단(null-terminator)이라고도 하는데, 문자열이 끝났으므로 더 이상의 문자가 남아있지 않다고 말하는 문자이다. 단순히 모든 비트가 0임을 나타내는 값으로, 1바이트를 차지한다. 따라서 문자열은 글자수+널(1byte)만큼의 공간을 차지하게 된다. 

문자열문자열
문자열 예시

(names 배열 4개라고 선언 해놓고 세개만 썼다.)

위의 코드에서 문자열 내의 값을 벗어난 널 종단까지 불러온다면 아래와 같다.

널 종단널 종단
널 종단까지 나타낸 결과

%c로 널 종단을 불러올 경우엔 아무런 변화가 없지만 %i로 불러올 경우엔 0이 나타난다.

강의에서 예시로 4글자를 가지는 문자열의 400번째 위치를 출력해본 결과 숫자 값이 출력되기도 했다. 이렇게 위치값 지정을 통해 컴퓨터의 메모리를 구석구석 살펴볼 수 있다고 한다.

 

6. 문자열의 활용

6.1 문자열의 길이

문자열문자열문자열
for 루프를 통해 문자열의 인덱스를 하나씩 증가시키면서 해당하는 문자를 출력하는 코드

문자열을 입력으로 받은 다음 for루프를 통해 문자열 내의 글자 하나하나(char)를 문자열내의 글자수만큼 출력해서 사실상 같은 글자를 출력해내고 싶다면 아래의 두가지 방법을 이용해 볼 수 있다.

  1. 문자열 내의 인덱스가 널 종단값과 다르다면(!=) 출력하도록 함 (아래 더보기 참고)
  2. <string.h>에 포함되어 있는 strlen이라는 문자열의 길이를 알려주는 함수를 사용

2번을 사용할 경우에는 일일히 널 종단값과의 비일치 여부를 검사할 필요없이 길이를 변수로 저장하고 변수만큼만 루프를 순환하기 때문에 1번과 비교했을 때 계산 방법도 보다 단순한데다 함수이기 때문에 사용하기에도 편리하다. 

 

6.2 소문자↔︎대문자 바꾸기

영문 소문자로 입력해주면 영문 대문자로 바꿔주는 함수의 코드를 작성하고자 할 때 가장 기본적인 방법은 아스키 코드(ASCII CODE)를 보면서 글자에 적용된 규칙을 파악한 뒤에 코드에 적용하는 것이다. 실제로 아스키 코드에서 문자를 살펴보면, 소문자의 경우 십진법으로 보았을때 해당 대문자 보다 각각 32만큼 크다. 

문자 바꾸기문자바꾸기
영문 소문자에서 대문자로 바꾸기

따라서 위의 예시처럼 문자가 소문자인지 확인한 뒤에 소문자라면 32만큼 빼주는 방식으로 대문자로 바꿔줄 수 있다. 즉, 소문자인지 검사후 소문자라면 값을 바꿔주고 대문자라면 그대로 출력하는 것이다. 

그러나 일일히 검사하고 대문자로 바꾸는 위의 식대신 (6.1 문자열의 길이와 마찬가지로)함수를 이용하여 보다 간단하게 표현할 수 있다.

toupper
toupper 함수 사용하기

 

C Library - - Tutorialspoint

C Library - The ctype.h header file of the C Standard Library declares several functions that are useful for testing and mapping characters. All the functions accepts int as a parameter, whose value must be EOF or representable as an unsigned char. All the

www.tutorialspoint.com

<Ctype.h>에 포함된 toupper을 사용하여 간단하게 소문자를 대문자로 바꾼 모습.

위의 두 예시를 통해 강의에서는 아스키코드와 32가 중요한게 아니라, 다른 사람이 만들어준 도우미 함수를 사용하는 것이 더 중요하다고 말한다.

✔️이처럼 코드를 짤 때에는 기존에 만들어진 함수들이 어떤 것들이 있는지 알고 이를 활용할 수 있는 것도 중요하다.

 

 

 

7. 명령행 인자

7.1 명령행 인자 예시

2강 C언어> 1. C기초> 1.2 소스코드와 머신코드에 정리했던 것처럼, clang 파일이름.c를 터미널에 입력할 경우 a.out이라는 머신코드를 생성해냈는데, 머신코드에 별도의 이름을 부여하고 싶을 경우 clang 뒤에 -o를 추가하여 clang -o 바꿀이름 현재파일명.c -lcs50이라고 입력해야한다. 이때 -o를 명령행 인자라고 한다. 

그래서 명령행 인자는 보통 실행하고자 하는 프로그램 뒤에 적는다. 이는 메인 함수 코드 int main (void)에서도 마찬가지로, (void)안에 특정 인자를 입력할 수 있다. 

명령행 인자
메인 코드 명령행 인자 예시

괄호 안을 살펴보면 정수와 문자열의 배열을 인자로 받고 있다. int 뒤의 변수이름과 string 뒤의 변수이름은 아무렇게나 적어도 되지만, 역시나 관습적인 표현에 따라 적은 모습이다.

  • argc(argument count)=인자 개수. 
  • argv(argument vector)=인자 벡터. 인자들의 배열이라는 뜻이다.

 

명령행 인자명령행 인자
메인코드 명령행 인자 주석 추가

예시 코드에 대해 주석을 추가하면 위와 같다. 즉, 이 코드는 사용자에게 프로그램을 실행 후 답을 입력하도록 하는 것이 아니라 명령 프롬프트에 바로 답(이 경우 이름)을 쓸 수 있도록 작성한 코드다. 

조금 더 자세히 풀어서 설명하자면, 이 두가지 명령행 인자에 따라 프로그램을 실행할 때 프로그램 이름 뒤에 단어를 입력하면 그 단어들은 argv배열에 들어가게 된다. CS50내에서 이와 같은 방식으로 작동하는 명령어들에는 clang, make, help50, style50, check50 등이 있는데, 모두 소스코드 파일 이름을 명령어 뒤에 입력해야만 작동한다.

이때 argc가 2인 이유(=argv[1]인 이유)는 처음에 입력하는 프로그램 이름 또한 배열에 저장되며, 인덱스의 처음에 위치하게 되기 때문이다.

argv[]argv[]
출력하는 argv[]를 '0'으로 설정할 경우

 

7.2 메인 함수의 반환값

메인 함수를 작성할 때 기본이 되었던 int main(void)는 결국 형식지정자 int + 변수 이름 main + (명령행 인자)를 뜻한다는 것을 알 수 있다.

그럼 왜 메인 함수는 반환값을 가지는 걸까? 강의에서는 '특별한 이유는 없다'고 압축한 뒤 '그렇게 중요한 건 아님'이라고 덧붙인다 ㅋㅋ 

(그러나 궁금하니까 계속해서 설명하자면,) C의 메인 함수는 기본적으로 반환값을 가지며, main은 0을 반환한다. 그리고 컴퓨터에서 0은 보통 문제 없음을 뜻한다. 0은 거짓이니까 안좋은 게 아닐까 싶지만, 좋은 뜻이라고 한다😅 왜냐하면 메인 함수는 0이 아닌 값들을 반환할 수도 있는데, 가령 에러가 발생했음을 알리는 팝업에 -42와 같은 숫자가 그 예다. 이는 사람들이 문제가 생기면 메인 함수가 반환하도록 정한 임의의 숫자라고 한다.

 

반환값 추가반환값 추가
반환값 추가

앞선 코드에서 인자 개수가 2개가 아닐 경우에는 에러 메시지가 나올 수 있도록 출력했다. 이때 return 뒤의 숫자는 설정하기 나름이지만 간단하게 1로 설정한 모습이다. 

 


어느덧 코칭스터디가 3주차를 돌파했다. 각 주차별 느낀점을 짤로 표현해봄.

우와오람너아ㅣ러
1주차

마냥 신기함

 

나는...슬픈...소라게...
2주차

갑자기 슬픈 소라게

 

오랑우탄 우당탕탕
3주차

실습하는 4학년과 1학년을 바라보는 교수.gif 라는 타이틀로 유명한 짤인데
저 안겨있는 오랑우탄의 모습이 불현듯 떠오름

우당탕탕 오랑우탄 짤 패러디

이번 주에 유독 코칭스터디를 취소하는 사람들이 많았는데 아마 나도 우리 조원들이 아니었으면 진작에 취소했을듯ㅎ


맥북 코딩 이미지 출처

 

Photo by AltumCode on Unsplash

More shots like this on my instagram pages - https://instagram.com/motivational.coder - https://instagram.com/grohsfabian. Download this photo by AltumCode on Unsplash

unsplash.com

러버덕 이미지 출처

 

Photo by Mpho Mojapelo on Unsplash

Download this photo by Mpho Mojapelo on Unsplash

unsplash.com

 

728x90