카테고리 없음

[혼공C] 2주차. Ch.3 변수 ~ Ch.4 연산자

H 기록 2024. 7. 12. 12:23
더보기

혼자 공부하는 C언어 2주차

 

Ch.03 -1 변수

변수 :  데이터를 저장하는 장소.

int a;

자료형 + 변수명의 형태로 선언하여 사용.

 

[자료형 종류]

정수형 short 2bytes %d
  int 4bytes %d
  long 4bytes %ld
  long long 8bytes %lld
  unsigned ~   %u
실수형 float 4bytes %f
  double 8bytes %lf
문자 char 1bytes %c
문자열 char arr[ ] 배열의 크기 %s

 

- 자료형의 종류에 따라 할당되는 메모리의 크기가 달라지는데, 이는 저장 가능한 데이터의 크기를 결정한다.

일반적으로 각 자료형에 할당되는 byte 수 중, 1 bit는 부호 비트로 사용한다.

int형을 예시로 설명하면,

int 는 4bytes를 할당받는 정수 자료형으로, 총 32bits 중 1bit는 부호 비트 (+ / -)로 사용된다. 따라서 -2^31 ~ 2^31-1까지 저장할 수 있는 것이다.

 

- unsigned를 사용하면 부호 비트로 사용하던 1bit도 데이터를 표현하는 데 사용되므로 0 이상의 수만 표현할 수 있으며 양수 범위가 늘어난다.

 

- 문자 자료형인 char은 하나의 문자를 저장할 수 있으며 ' ' (작은 따옴표) 안에 문자를 넣어 저장한다.

char a = 'A';

문자열의 경우 여러 개의 문자를 하나의 변수에 저장하는 것으로, 문자가 저장되는 배열을 사용해야 한다. 이때 배열의 크기는 저장하고자 하는 (문자열의 길이 + 1) 이상으로 정해야하는데, 이는 컴파일러가 문자열의 끝에 자동으로 '\0'(널 문자)를 추가하기 때문이다. 만약 문자열의 길이만큼만 크기를 잡는다면, 문자열이 완전히 저장될 공간이 부족해서 오류가 발생할 수 있다.

 

 

- 자료형 변수명 ; 의 형식으로 변수를 선언하면, 자료형에 해당하는만큼의 메모리가 변수에 할당되고, 그 메모리에는 쓰레기 값이 저장되어 있다. 따라서 초기 값인 쓰레기 값을 초기화해야 원하는 프로그램을 작성할 때 오류가 발생하지 않는다. 

int a;
a = 1 

int b = 3

초기화는 오른쪽 값을 왼쪽에 저장(할당)한다는 의미를 가지는 대입 연산자(=)를 활용한다. 두 가지 방법 전부 초기화가 가능하다.

 

- const를 사용한 변수

const 는 constant의 약자로, 뒤에 오는 변수를 상수처럼 사용한다는 의미이다. 저장과 수정이 자유로운 변수와 달리 상수는 처음 초기화할 때 할당했던 값을 수정하는 것이 불가능하다. 따라서 const를 사용할 경우 선언과 동시에 초기화가 필요하다. 

 

[예제]

1.  변수 할당 및 초기화

#include <stdio.h>

int main(){
    int a;
    int b, c;
    double da;
    char ch;

    a = 10;
    b = a;
    c = a + 20;
    da = 3.5;
    ch = 'A';

    printf("변수 a = %d\n", a); // 예상 값 10
    printf("변수 b = %d\n", b); // 10
    printf("변수 c = %d\n", c); // 30
    printf("변수 da = %lf\n", da); //3.500000
    printf("변수 ch = %c\n", ch); // A

    return 0;
}

 

2. 출력 형식 지정

#include <stdio.h>

int main(){
    char ch1 = 'A';
    char ch2 = 65;

    printf("문자 %c의 아스키코드 값 : %d\n", ch1, ch1);
    printf("아스키코드 값이 %d인 문자 : %c\n", ch2, ch2);

    //출력 방식을 다른 자료형으로 설정하면 그 자료형의 형태로 출력됨.
    //문자를 정수형으로 출력하면 해당 문자의 아스키코드 값이 출력.
}

 

4. unsighed 자료형

#include <stdio.h>

int main(){
    unsigned int a;

    a = 4294967295;
    printf("%d\n", a); // -1 출력
    
    a = -1;
    printf("%u\n", a); // 4294967295 출력
}

해당 코드를 실행하면, 할당한 값과는 다른 결과가 출력된다.

우선 %d는 정수형의 출력 형태로, 양수의 경우 최대 2,147,483,647( 2 ³¹ - 1)까지 저장할 수 있다. 하지만 해당 코드에서는 가능한 최대값 이상의 수를 정수형으로 출력하려고 시도하므로 오류가 발생한다. 일반적인 자료형의 경우 음수는 음의 보수법을 사용해서 저장하는데, a 에 저장된 4294967295는 이진수로 11111111 11111111 11111111 11111111에 해당하며 이는 음의 보수법에 따르면 -1을 표현한다.

 

%u는 unsigned 자료형의 형태로, 부호 비트를 사용하지 않기 때문에 부호를 무시하고 양수로 처리한다. 따라서 -1을 출력하려고 할 경우 해당하는 양수 값을 출력하는 것이다.

 

6. 문자열 저장

#include <stdio.h>

int main(){
    char fruit[20] = "strawberry";

    printf("딸기 : %s\n", fruit);
    printf("딸기잼 : %s %s\n", fruit, "jam");
    
}

문자 배열 fruit[20]에 인덱스 하나에 문자 하나가 저장된다. 이때 배열의 이름인 fruit는 fruit[0], 즉 배열이 시작되는 메모리의 주소로, 문자열의 주소로 사용된다. 

 

Ch. 03 - 2 데이터 입력

- scanf 함수

scanf("%자료형", 변수 주소);

int a;
scanf("%d", &a);

사용자의 터미널에서 값을 입력받아 변수에 저장하는 함수로, 직접 할당하는 것이 아니라 입력받은 값을 할당하는 것이기 때문에 변주의 주소를 입력해야 한다. 그리고 입력 받을 값의 자료형에 맞는 변환 문자를 사용해야 한다.

 

문자열의 경우, 문자형 배열에 문자열 전체가 저장되는데, 이때 배열명이 주소를 나타낸다. 따라서 문자열을 입력받을 경우 주소 연산자인 &(엠퍼센트)를 사용하지 않아야 한다. (문자열을 저장하는 변수명 자체가 주소를 나타내기 때문!) 혹은 아래와 같이 표현할 수도 있다.

char arr[20];

scanf("%s", arr);
scanf("%s", &arr[0]);

두 형태가 같은 의미를 가진다.

 

 

[확인 문제]

1. 다음과 같이 변수가 선언되어 있을 때, scanf 함수의 사용법은?

#include <stdio.h>

int main(){

    char ch;
    scanf("%c", &ch);
    
    short sh;
    scanf("%hd", &sh);

    int in;
    scanf("%d", &in);

    float ft;
    scanf("%f", &ft);

    double db;
    scanf("%lf", &db);
}

답은 3번

 

2. 프로그램 완성하기

#include <stdio.h>

int main(){
    char fruit[20];
    int cnt;

    printf("좋아하는 과일 :");
    scanf("%s", fruit);
    printf("몇 개 : ");
    scanf("%d", &cnt);
    printf("%s를 %d개 드립니다.", fruit, cnt);

    return 0;
}

 

3. 프로그램 완성하기

#include <stdio.h>

int main(){
    char ch;
    printf("문자 입력: ");
    scanf("%c", &ch);

    printf("%c의 아스키 코드 값은 %d입니다.", ch, ch);
}

 

 


Ch.4 연산자

-1. 산술 연산자, 관계 연산자, 논리 연산자

(1) 산술 연산자

덧셈 +
뺄셈 -
곱셈 *
나눗셈 /
나머지 % 나머지
대입 =  할당

곱셈과 나눗셈의 경우 피연산자 중 하나라도 실수(부동 소수점형)형태이면, 출력 형태를 실수로 지정한 후 출력하면 실수 형태로 출력된다.

 

(2) 증감 연산자

++ : 1 증가

-- : 1 감소

 

변수 앞에 증감 연산자를 위치시키는 전위 표기, 뒤에 위치시키는 후위 표기가 있다.

전위 표기는 값이 증감한 후 연산에 사용되고, 후위 표기는 연산에 사용하고 나서 값이 증감한다. (순서의 차이!)

 

(3) 관계 연산자

크다 >
작다 <
같다 ==
같지 않다 !=
크거나 같다 >=
작거나 같다 <=

 

대입 연산자인 = 는 오른쪽의 값을 왼쪽에 저장한다는 의미이고, 관계연산자인 == 는 왼쪽과 오른쪽의 값이 같다 라는 의미이다. 

즉 대입 연산자는 변수 메모리에 값을 저장 혹은 할당할 때, 관계 연산자는 변수에 저장된 값이 이 값이 맞는지 확인할 때 사용한다.

 

(4) 논리 연산자

AND &&
OR ||
NOT !

 

AND : 두 항이 모두 참인 경우에만 참

OR : 두 항 중 하나라도 참이면 참

NOT : 부정

 

-2 그 외 유용한 연산자

(1) 형 변환 연산자

(자료형) 피연산자

-> 피연산자의 원래 자료형에서 괄호 안의 자료형으로 형태를 변환하는 데 사용한다. 피연산자의 자리에는 데이터 값이 직접 들어가거나, 데이터가 저장되어 있는 변수명을 넣을 수도 있다.

 

(2) sizeof 연산자

sizeof(피연산자)

-> 피연산자에 할당된 메모리의 크기를 계산해서 알려주는 연산자로, 피연산자에는 변수, 상수, 수식, 자료형 등이 들어갈 수 있다.

메모리를 동적으로 할당할 때, 그 크기를 지정하기 위해 유용하게 사용된다.   

 

(3) 복합 대입 연산자

a += b a = a + b
a -= b a = a - b
a *= b a = a * b
a /= b a = a / b
a %= b a = a % b

 

(4) 콤마 연산자

int a = 10
int b = 20;

int res;

res = (++a, ++b);

콤마 연산자는 이어지는 연산을 왼쪽에서부터 차례대로 진행할 때 사용한다. 

우선순위가 대입 연산자보다 낮아서, 괄호가 없을 경우 제일 처음 연산되는 값이 대입된 후 다음 연산이 진행되고 괄호가 있을 경우 연산이 끝난 후 마지막 값이 대입된다.

 

위 코드의 경우, res에는 ++b한 21이 저장되며, a = 11, b = 11이 저장된다.

 

(5) 조건 연산자

(a > b) ? a : b

a > b가 참이면? a, 거짓이면? b 라는 뜻

 

(6) 비트연산자

데이터를 비트(bit) 단위로 연산하는 연산자로, 이진수로 표현한 후 연산하는 것이라고 생각하면 된다.

논리곱(AND) &
논리합(OR) |
배타적 논리합(XOR) ^
부정(NOT) ~
비트 이동 >> 혹은 <<

 

비트 이동 시 연산자 뒤에 숫자로 이동 횟수를 표시한다. 이때 오른쪽 비트 연산은 1번 이동할 때마다 2로 나눈 것과 같고, 왼쪽 비트 연산은 1번 이동할 때마다 2를 곱한 것과 같다. 이동 후 남는 비트는 0으로 채워진다. 

 

[확인 문제]

1. short와 long의 자료형 크기 비교

#include <stdio.h>

int main(){
    int res;

    int long_;
    int short_;

    long_ = sizeof(long);
    short_ = sizeof(short);

    res = (long_ < short_) ? 1 : 0;

    if(res == 1){
        printf("short");
    }
    else{
        printf("long");
    }
}

 

2. 입장률 계산

#include <stdio.h>

int main(){
    int seats = 70;
    int audience = 65;

    double rate;

    double d_searts = (double)seats;

    rate = audience / d_searts * 100;

    printf("입장률 : %.1lf%%",rate);
}

입장률을 계산할 때는 나눈 후 100을 곱하는데, 이때 정수형끼리 나누면 항상 몫이 0이므로 실수형으로 변환해야 한다. 

(double) seats 로 변환해주었다.

 

출력할 때 %는 포맷 출력을 위한 기호로 사용되어 다른 문자처럼 입력한다고 해서 출력되지 않는다. %를 출력하기 위해서는 %%를 입력해야 출력된다. 이외에도 연산자로 사용되는 것을 출력하고자 할 때는 앞에 \(백슬래시)를 붙여 문자로 출력할 것임을 표시하면 된다.

 

3. 시간, 분, 초 계산

#include <stdio.h>

int main(){
    int hour, min, sec;
    double time = 3.76;
    double temp = time;

    hour = (int)temp; //double형에서 int로 변환. 3.76 --> 3
    temp = temp - hour; // 1시간이 넘는 부분을 제외. 0.76

    temp = temp * 60; // 분 단위 계산 0.76 * 60
    min = (int)temp; //분 단위 계산한 값 중 1분이 넘는 부분 저장. 
    temp = temp - min; //1분이 넘는 부분 제외. 

    temp = temp * 60; // 초 단위 계산
    sec = temp; // 초 단위 저장

    printf("%.2lf 시간은 %d 시간 %d 분 %d 초 입니다.", time, hour, min, sec);
}

 출력할 때, 포맷 형식 앞에 .(숫자)를 붙이면 소수점 아래 몇째자리까지 출력할 지 정할 수 있다.

 

 

[도전 실전 예제]

체중 관리 프로그램 

#include <stdio.h>

int main(){
    printf("[BMI 계산 프로그램]\n");


    int kg, cm;

    printf("몸무게(kg) 과 키(cm) 입력 : ");
    scanf("%d %d",&kg, &cm);

    double bmi = kg / ((cm * 0.01)*(cm*0.01));

    if(bmi >= 20.0 && bmi <= 25.0){
        printf("BMI = %.1lf \n표준입니다.\n", bmi);
    }
    else{
        printf("BMI = %.1lf \n체중 관리가 필요합니다.\n", bmi);
    }
}

연산자의 우선순위가 헷갈리는 경우, 먼저 계산해야 하는 연산을 괄호로 묶어 우선순위를 지정할 수 있다.