cs50 2강
KeyWord
- 컴파일러와 헤더파일
- 문자열과 string
- 자료형과 연산자
- 사용자 정의 함수
- 오버플로우
C기초
#include <stdio.h>
int main(void)
{
printf("hello, world\n");
}
이 코드에서 include 부분은 내가 어떤 헤더파일을 불러오겠다고 명시하는 부분이다.
헤더파일은 일종의 약속같은 것이자, 기능의 제공이기도 하다.
즉 stiod.h
는 내가 c언어로 앞으로 코드를 작성하겠다는 약속이자, 일종의 입출력의 편의를 제공하는 기능 제공의 역할도 동반하고 있는 것이다.
컴파일러는 이때 우리가 작성한 소스코드를 output하여 프로그램을 컴퓨터가 실행할 수 있게끔 도와주는 역할을 한다.
컴파일러와 헤더파일의 관계
자, 헤더파일은 아까 기능의 제공이라고 했다.
그것은 사실 철저하게 사용자의 관점에서 해석된 내용으로 컴파일러에게 헤더파일은 길라잡이와 같은 존재이다.
우리가 printf
를 작성하면, 사실 컴파일러는 stdio.h
안에서 printf
라는 함수를 찾아 그 형식에 맞게 인자가 전달되었다면 함수를 실행시켜주는 것 뿐이다.
따라서 컴파일러에게 헤더파일은 안내자와 같은 역할을 한다고 볼 수 있다.
기본 코드 규약
c언어에서는 문자를 출력하기 위해서는 원하는 문자를 따옴표 안에 감싸서 표현한다.
또한 줄바꿈은 ` “\n`표시를 통해 나타낸다.
문자열
위에서 말한 string은 사실 문자열임을 알려주는 형식지정자이다.
C언어는 고물 구닥다리 언어이기 때문에, 우리가 작성하는 코드가 무엇을 의미할지 즉 문자인지 숫자인지 등을 모두 미리 알려주어야하는데 string은 변수의 내용물이 여러개의 문자로 이루어진 문자열임을 명시해주는 역할을 한다.
할당 연산자
할당 연산자는 변수라는 그릇에다 담을 내용물을 담아주는 역할을 한다.
즉 변수라는 그릇과 문자열 내용물이 있더라도 =
이라는 할당 연산자가 없다면 이 둘은 분리된 존재로 아무런 연관성을 가질 수 없다는 것이다.
get_string
get_string함수는 어떠한 단어나 문장을 호출해주는 역할로, 변수라는 그릇에 담을 내용물을 넣을 수 있다.
종합 코드
string answer = get_string("What's your name?\n");
printf("hello, %s\n", answer);
여기에서 나오는 %s
는 형식 지정자의 일종으로, answer에 담길 내용물이 string이기 때문에 string의 약자를 따서 %s
로 작성하기로 약속한 것이다.
조건문과 루프
컴퓨터에게 어떤 행동을 지시할 때에 행동을 반복시킨다거나, 특정 조건이 참이냐 거짓이냐에 따라 다른 행동을 실행하고 싶을 때가 있다.
이때 사용하는 것이 각각 루프문과 조건문이다.
C언어 루프문
크게 while과 for문으로 나눌 수 있다.
while로 만약에 무한루프를 주고 싶다면 while(true)
또는 while(1)
을 사용하면 된다.
루프문 선택법
- for은 반복횟수가 명확하게 정해졌을 때(ex.구구단)사용하면 좋다.
- while은 무한루프를 주면서 특정 지점에서 break를 걸 때에 용이
- for은 초기화와 조건검사 및 반복작업을 유연하게 결합시키기에 용이
조건문
if조건문에는 세미콜론을 붙이지 않고 함수처럼
{}
를 붙인다.
이는 조건문은 완벽한 statement(문장)이 아닌 일종의 코드 블럭 지시에 가깝기 때문이다.
즉 조건문만 작성하여서는 어떤 역할도 할 수 없기 때문에 문장 취급이 아닌 함수와 같은 지시자와 유사하게 취급하여 세미콜론이 아닌{}
를 붙이기로 약속한 것이다.자료형, 형식 지정자, 연산자
자료형
자료형 | 바이트 수 | 역할 |
---|---|---|
char | 1 | 문자(character) 저장에 사용됨 |
int | 4 | 정수(integer) 저장에 사용됨 |
float | 4 | 부동 소수점 숫자 저장에 사용됨 |
double | 8 | 더 큰 범위의 부동 소수점 숫자 저장에 사용됨 |
short | 2 | 작은 정수 저장에 사용됨 |
long | 8 | 더 큰 범위의 정수 저장에 사용됨 |
long long | 8 | 아주 큰 범위의 정수 저장에 사용됨 |
unsigned | 4 | 부호 없는 정수 저장에 사용됨 |
signed | 4 | 부호 있는 정수 저장에 사용됨 |
위 표는 자료형의 크기와 역할에 대해 간략하게 나타낸 표이다.
구닥다리 언어인 c언어는 변수(그릇)을 선언하기 이전에 이것이 어떤 용도의 그릇인지 표기를 해주어여만 한다.
즉 자료형은 일종의 그릇의 용도를 미리 알려주기 위한 약속과 같은 것이다.
형식 지정자
형식 지정자 | 역할 |
---|---|
%d | 10진수로 정수를 입력 받거나 출력할 때 사용 |
%f | 부동 소수점 형식의 숫자를 입력 받거나 출력할 때 사용 |
%c | 문자(character)를 입력 받거나 출력할 때 사용 |
%s | 문자열(string)을 입력 받거나 출력할 때 사용 |
%x | 16진수로 정수를 입력 받거나 출력할 때 사용 |
%o | 8진수로 정수를 입력 받거나 출력할 때 사용 |
%u | 부호 없는 정수를 입력 받거나 출력할 때 사용 |
%p | 메모리 주소를 입력 받거나 출력할 때 사용 |
%% | % 기호를 출력할 때 사용 |
형식 지정자는 출력 시 그 변수가 어떤 역할을 하는지 명시해주는 역할을 한다.
참고로 float과 double의 경우 소수를 나타낸다는 것은 동일하나, 정확도가 다르므로 정밀도에 따라 골라 사용하여야한다.
연산자와 우선순위
연산자 | 우선순위 | 설명 |
---|---|---|
* / % | 1순위 | 곱하기, 나누기, 나머지 연산자 |
+ - | 2순위 | 더하기, 빼기 연산자 |
&& | 3순위 | 그리고 논리 연산자 |
|| | 4순위 | 또는 논리 연산자 |
우선순위에 따라 내가 예상한 값이 나오지 않을 수 있기 때문에, 우선순위를 잘 모르겠다면 괄호를 사용하는 것이 안전하다.
사용자 정의 함수와 중첩 루프
c언어는 오래되었기 때문에, main의 아래에 작성한 함수들에 대해서는 제대로 불러오지 못하는 문제가 발생한다.
따라서 인간 논리의 순서대로가 아니라, 미리 함수를 위에 작성해놓고 main에서 불러오는 방식을 사용하여아한다.
그러나, 이러한 방식은 몇몇 불편함을 야기하기 때문에 컴파일러를 속일 수 있는 꼼수가 존재한다.
함수를 불러들이는 함수
#include <stdio.h>
void cough(void);
int main(void)
{
for (int i = 0; i < 3; i++)
{
cough();
}
}
void cough(void)
{
printf("cough\n");
}
이렇게 작성해서 위에있는 cough
라는 함수를 3번 반복문을 돌도록 하고 아래에서 사용자 함수를 재정의 해주면 된다.
함수를 미리 선언하는 이러한 방식을 함수 프로토 타입
이라고 부른다.
do-while
아까 말한 while의 약간 응용판이다.
while문의 조건을 충족시킬 때까지 do 안에 담긴 코드 블록의 내용물을 반복하여 실행하는 방식이다.
이중 루프
이중 루프는 단순하게 설명하면 for를 두개 감싸서 외부와 내부의 반복 수를 다르게 조절하는 것이다.
유의할 것은 for문은 가장 내부의 루프부터 바깥쪽 루프의 순으로 순차적으로 선언된 변수가 적용되기 때문에 안쪽 루프가 좀 더 우선적으로 반복된다는 것이다.
뭔소리지?
#include <stdio.h>
int main() {
for (int i = 0; i < 3; i++) {
printf("Outer loop, i = %d\n", i);
for (int j = 0; j < 2; j++) {
printf("Inner loop, j = %d\n", j);
}
}
return 0;
}
이 코드를 실행하면 실행시 나오는 결과값은 다음과 같다.
Outer loop, i = 0
Inner loop, j = 0
Inner loop, j = 1
Outer loop, i = 1
Inner loop, j = 0
Inner loop, j = 1
Outer loop, i = 2
Inner loop, j = 0
Inner loop, j = 1
C언어가 가지고 있는 문제들
사실 c언어만이 가지고 있는 문제라기 보다는 메모리의 용량에 따른 문제에 가깝다.
부동소수점 오류
float는 double형에 비해 저장가능한 소수점 아래 비트수가 작다.
그렇다보니, 정밀한 연산을 진행시키게 되면 계속해서 오차가 조금씩 늘어나게 되는데 이를 부동소수점 오류라 부른다.
오버플로우
오버플로우는 자료형이 표현할 수 있는 범위를 넘어섰을 때 발생하게 된다.
int의 자료형이 표현할 수 있는 값을 벗어나면 내가 출력하고자 하는 값이 아닌 엉뚱한 값이 출력된 적 있을 것이다.
이것을 바로 오버플로우라고 부른다.
댓글남기기