리스트 7.1 colddays.c 프로그램
// colddays.c -- 영하로 내려간 날들의 백분율을 구한다.
#include<stdio.h>
int main(void)
{
const int FREEZING = 0;
float temperature;
int cold_days = 0;
int all_days = 0;
printf("최저 기온들의 목록을 입력하시오.\n");
printf("섭씨 단위를 사용하시오(입력을 끝내려면 q):\n");
while (scanf("%f",&temperature) == 1)
{
all_days++;
if (temperature < FREEZING)
cold_days++;
}
if(all_days != 0)
printf("전체 %d일 중에 영하의 날씨는 %.1f%%였습니다.\n",all_days, 100.0 * (float) cold_days / all_days);
if(all_days == 0)
printf("입력된 데이터가 없습니다! \n");
return 0;
}
<코드분석>
첫번 째 if 문(while 안에 if 문)
while (scanf("%f",&temperature) == 1)
{
all_days++;
if (temperature < FREEZING)
cold_days++;
}
temperature이 0보다 작으면 cold_days를 1씩 증가 시킨다.
만약 temperature이 0보다 크다면 cold_days++; 문 을 지나가고 다음 기온의 값을 읽는다.
두번 째 if문과 세번째 if문
if(all_days != 0)
printf("전체 %d일 중에 영하의 날씨는 %.1f%%였습니다.\n",
all_days, 100.0 * (float) cold_days / all_days);
if(all_days == 0)
printf("입력된 데이터가 없습니다! \n");
all day가 0이 아니면 즉 데이터가 있으면 결과를 출력하고 아니면 없다고 보고한다,
리스트 7.2 cypher.c 프로그램
// cypher1.c -- 스페이스는 유지하고,입력을 변경한다
#include<stdio.h>
#define SPACE ' ' // 작은따음표-스페이스-작은 따음표
int main(void)
{
char ch;
ch = getchar(); // 문자 하나를 읽는다
while (ch != '\n') // 라인의 끝이 아닌동안
{
if (ch == SPACE) // 스페이스는 그대로 둔다.
putchar(ch); // 변경하지 않는다
else
putchar(ch + 1); // 다른 문자들은 변경
ch = getchar(); // 다음 문자를 얻는다
}
putchar(ch); // 개행을 출력
return 0;
}
<코드분석>
상수 정의
#define SPACE ' '
- #define SPACE ' '는 매크로 정의. 여기서 SPACE라는 이름을 공백 문자 ' '에 대해 정의.
- 이후 코드에서 SPACE라고 쓰면, 컴파일러는 이를 공백 문자로 해석. 이 방법을 사용하면 공백 문자를 더 쉽게 참조할 수 있고, 코드의 가독성이 좋아짐
main 함수
프로그램의 시작점인 main 함수.
int main(void)
{
char ch;
- char ch;: ch라는 이름의 문자형 변수를 선언. 이 변수는 사용자가 입력한 문자 하나를 저장하는 데 사용된다.
문자 입력 받기
ch = getchar();
- getchar()는 사용자가 키보드로 입력한 한 문자를 읽어들여 반환하는 함수
- 이 코드에서는 사용자가 입력한 첫 번째 문자를 받아서 ch 변수에 저장
반복문 시작
while (ch != '\n')
- while은 반복문으로, 조건이 참일 때 계속해서 반복.
- 여기서는 ch가 줄 바꿈 문자('\n')가 아닐 때까지 반복. 즉, 사용자가 엔터 키를 누를 때까지 반복.
조건문과 출력
if (ch == SPACE)
putchar(ch);
else
putchar(ch + 1);
if (ch == SPACE)는 ch가 공백 문자(' ')인지 확인.
- 만약 ch가 공백이면, putchar(ch);가 실행. putchar는 하나의 문자를 출력하는 함수. 여기서는 공백 문자를 그대로 출력한다.
- 만약 ch가 공백이 아니라면, else 구문이 실행된다. putchar(ch + 1);는 ch에 1을 더한 값을 출력한다. 문자에 1을 더한다는 것은 그 문자의 다음 문자를 의미. 예를 들어, a에 1을 더하면 b가 된다.
다음 문자 읽기
ch = getchar();
- 다음 문자를 입력받아 ch에 저장합니다. 이 과정이 반복문 안에서 계속 실행되어, 사용자가 줄 바꿈 문자를 입력할 때까지 반복.
줄 바꿈 문자 출력
putchar(ch);
- 반복문이 종료된 후, ch에는 줄 바꿈 문자('\n')가 저장되어 있습니다. 이 줄 바꿈 문자를 그대로 출력하여, 프로그램이 정상적으로 종료되도록 한다.
프로그램의 전체 동작
- 사용자가 문자열을 입력.
- 프로그램은 사용자가 입력한 각 문자를 하나씩 읽어들인다.
- 읽어들인 문자가 공백이면 그대로 출력.
- 읽어들인 문자가 공백이 아니면, 그 문자의 다음 문자를 출력.
- 사용자가 엔터 키를 누르면, 프로그램은 줄 바꿈 문자를 출력하고 종료.
예시 실행
사용자가 hello world를 입력하면, 프로그램은 ifmmp xpsme를 출력. 여기서 h는 i로, e는 f로, l은 m으로 바뀌었으며, 공백은 그대로 유지.
리스트 7.3 cypher2.c 프로그램
// cypher2.c -- 알파벳 문자가 아닌 것들은 유지하고, 입력을 변경한다
#include<stdio.h>
#include<ctype.h>
int main(void)
{
char ch;
while ((ch =getchar()) != '\n')
{
if (isalpha(ch)) // 문자이면
putchar(ch + 1); // 다음 문자를 출력
else // 문자가 아니면
putchar(ch); // 그대로 출력
}
putchar(ch); // 개행을 출력
return 0;
}
<코드분석>
getchar() 함수는 전달인자가 알파벳 문자면 0이 아닌 값을 리턴하는 함수다.
리스트 7.4 electric.c 프로그램
// electric.c --전기요금을 계산한다.
#include <stdio.h>
#define RATE1 0.13230 // 처음 360kwh 까지 적용하는 비율
#define RATE2 0.15040 // 그 다음 108 kwh 까지 적용하는 요율
#define RATE3 0.30025 // 그 다음 252 kwh 까지 적용하는 요율
#define RATE4 0.34025 // 720 kwh를 초과할 때 적용하는 요율
#define BREAK1 360.0 // 요율의 첫 번째 구분점
#define BREAK2 468.0 // 요율의 두 번째 구분점
#define BREAK3 720.0 // 요율의 세 번째 구분점
// 360kwh에 대한 요금
#define BASE1 (RATE1 * BREAK1)
// 468kwh에 대한 요금
#define BASE2 (BASE1 + (RATE2 * (BREAK2 - BREAK1)))
// 720kwh에 대한 요금
#define BASE3 (BASE1 + BASE2 + (RATE3 * (BREAK3 - BREAK2)))
int main(void)
{
double kwh; // 사용할 전력량
double bill; // 부과할 전기요금
printf("사용한 전력량을 입력하시오.\n");
scanf("%lf", &kwh); // double형을 위해 %lf를 사용
if (kwh <= BREAK1)
bill = RATE1 * kwh;
else if (kwh <= BREAK2) // 사용한 전력량이 360과 468사이
bill = BASE1 + (RATE2 * (kwh - BREAK1));
else if (kwh <= BREAK3) // 사용한 전력량이 468과 720사이
bill = BASE2 + (RATE3 * (kwh - BREAK2));
else // 사용한 전력량이 720을 초과
bill = BASE3 + (RATE4 * (kwh - BREAK3));
printf("%.1f kwh의 전기요금은 $%1.2f입니다.\n", kwh, bill);
return 0;
}
<코드분석>
각 전력량 마다 부과되는 금액을 부여하는 프로그램이다.
특이점은 else if를 썻다 파이썬에서 elif와 같은 문구다,
리스트 7.5 divisor.c프로그램
// divisors.c -- 중첩된 if문들이 어떤 수의 약수들을 출력한다.
#include<stdio.h>
#include<stdbool.h>
int main(void)
{
unsigned long num; // 검사를 위해 주어지는수
unsigned long div; // 잠정적인 약수
bool isPrime; // 소수 플래그
printf("검사할 정수를 하나 입력하시오.");
printf("(끝내려면 q)\n");
while (scanf("%lu",&num) == 1)
{
for (div = 2, isPrime = true; (div * div) <= num; div++)
{
if (num % div == 0)
{
if((div * div) != num)
printf("%lu,%lu: 둘 다 %lu의 약수다.\n",div, num / div, num);
else
printf("%lu: %lu의 약수.\n",div,num);
isPrime = false; // 소수가 아니다
}
}
if(isPrime)
printf("%lu: 소수다.\n",num);
printf("검사할 또 다른 정수를 하나 입력하시오");
printf("(끝내려면 q)\n");
}
printf("안녕\n");
return 0;
<코드 분석>
첫번 째 for문
for (div = 2, isPrime = true; (div * div) <= num; div++)
2부터 시작하여 2가 1씩 증가하게 만든다 예를 들어 사용자에게 num을 16을 받았다면
2 * 2 = 4 <= 16 보다 작으니 참
3 * 3 = 9 <= 16 보다 작으니 참
4 * 4 = 16 <= 16 과 같으니 참
5 * 5 = 25 <= 16 보다 크니 거짓 임으로 첫번 째 for문에는 2,3,4,가 저장이된다.
for문안에 있는 if문
if (num % div == 0)
첫번째 for문에서 2,3,4가 div안에 대입된다. 아까 사용자에게 16을 입력 받았음으로
16 % 2 == 0 이되므로 참
16 % 3 == 1 이되므로 거짓
16 % 4 == 0 이되므로 참
이렇게 3이 걸러지게된다.
그러면 2,4가 남게된다.
for문안에 있는 if else 문
if((div * div) != num)
printf("%lu,%lu: 둘 다 %lu의 약수다.\n",div, num / div, num);
else
printf("%lu: %lu의 약수.\n",div,num);
첫번째 for문에서 2와 4가 각각 곱해진다
2 * 2 = 4 이건 16과 같지 않기 때문에 if문 안에있는 printf가 출력된다
4 * 4 = 16 이건 16과 같기 때문에 else문이 출력된다.
if(isPrime)
printf("%lu: 소수다.\n",num);
첫번째 for문에서 div * div <= num num이 11이였을때 1,2,3, 이 나오지만 그다음에 나오는
if문에서 모두 11 % div == 0 이 참이 아니기 때문에 다음의 "소수다"가 출력이 된다.
리스트 7.6 chcount.c 프로그램
// chcount.c -- 논리 연산자 AND를 사용한다.
#include<stdio.h>
#define PERIOD '.'
int main(void)
{
int ch;
int charcount = 0;
while ((ch =getchar()) != PERIOD)
{
if (ch != '"' && ch != '\'')
charcount++;
}
printf("따음표는 빼고, 문자 %d개가 들어 있습니다.\n",charcount);
return 0;
}
<코드분석>
getchar()로 사용자에게 문자를 입력받고 .(마침표)를 빼고 숫자를 계산하는 프로그램
논리연산자 &&
if (ch != '"' && ch != '\'')
charcount++;
여기서 &&는 AND 그리고라는 뜻이다 "와 '를 빼고 문자 카운터를 해라~ 라는 문장이다.
논리 연산자 | 의미 |
&& | 논리곱 AND |
|| | 논리합 OR |
! | 논리부정 NOT |
논리 연산자를 대신할 수 있는 표기
전통적 표기 | iso646.h |
&& | and |
|| | or |
! | not |
리스트 7.7 wordcnt.c 프로그램
// wordcnt.c -- 문자 수, 단어 수, 라인 수를 카운트한다.
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define STOP '|'
int main(void)
{
char c; // 현재 읽은 문자
char prev; // 바로 전에 읽은 문자
long n_chars = 0l; // 문자 수
int n_lines = 0; // 라인 수
int n_words = 0; // 단어 수
int p_lines = 0; // 불완전 라인 수
bool inword = false; // c가 여전히 한 단어 안에 속해 있으면 true
printf("분석할 영문 텍스트를 입력하시오(끝내려면 |):\n");
prev ='\n'; // 완전 라인을 식별하는 데 사용된다
while ((c = getchar()) != STOP)
{
n_chars++; // 문자를 카운트한다
if (c == '\n')
n_lines++; // 라인을 카운트한다
if(!isspace(c) && !inword)
{
inword = true; // 새 단어를 시작한다
n_words++; // 단어를 카운트한다
}
if (isspace(c) && inword)
inword = false; // 단어의 끝에 도달한다
prev = c; // 문자의 값을 보관한다
}
if (prev != '\n')
p_lines = 1;
printf ("문자 수 = %ld, 단어 수 = %d, 라인 수 = %d,",n_chars,n_words,n_lines);
printf(" 불완전 라인 수 = %d\n",p_lines);
return 0;
}
<출력>
분석할 영문 텍스트를 입력하시오(끝내려면 |):
Reason is a
powerful servant but
an inadequate master.
|
문자 수 = 55, 단어 수 = 9, 라인 수 = 3, 불완전 라인 수 = 0
<코드 분석>
헤더 파일과 상수 정의
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
#define STOP '|'
- #include <stdio.h>: 표준 입출력 함수들을 사용하기 위해 포함하는 코드. printf, getchar 같은 함수들을 사용할 수 있다.
- #include <ctype.h>: isspace 같은 문자 처리를 위한 함수들을 사용하기 위해 포함하는 코드
- #include <stdbool.h>: bool 자료형을 사용하기 위해 포함하는 코드. bool 자료형은 true(참) 또는 false(거짓) 값을 가질 수 있다
- #define STOP '|': 사용자가 입력을 종료할 때 사용할 문자를 정의. 이 프로그램에서는 | 문자를 입력하면 입력이 종료됨.
변수 선언
char c; // 현재 읽은 문자
char prev; // 바로 전에 읽은 문자
long n_chars = 0l; // 문자 수를 세기 위한 변수
int n_lines = 0; // 라인 수를 세기 위한 변수
int n_words = 0; // 단어 수를 세기 위한 변수
int p_lines = 0; // 불완전 라인 수를 세기 위한 변수
bool inword = false; // 현재 문자가 단어 안에 있는지를 추적하는 변수
- char c: 사용자가 입력한 현재 문자를 저장하는 변수.
- char prev: 바로 이전에 입력된 문자를 저장하는 변수.
- long n_chars = 0l: 입력된 전체 문자의 수를 저장하는 변수. 0l로 초기화하여 처음에는 문자가 없음을 나타낸다.
- int n_lines = 0: 입력된 전체 줄(라인)의 수를 저장하는 변수.
- int n_words = 0: 입력된 전체 단어의 수를 저장하는 변수.
- int p_lines = 0: 불완전한 줄의 수를 저장하는 변수이다. 불완전한 줄은 마지막에 \n(줄바꿈 문자) 없이 종료된 줄을 의미한다.
- bool inword = false: 현재 문자가 단어 안에 있는지 여부를 추적하는 변수. 초기값은 false로 설정되어 있다.
사용자 안내와 입력 받기
printf("분석할 영문 텍스트를 입력하시오(끝내려면 |):\n");
prev = '\n'; // 완전 라인을 식별하는 데 사용된다
- printf: 사용자에게 텍스트 입력을 요청하는 메시지를 출력한다. | 문자를 입력하면 텍스트 입력이 종료된다는 의미.
- prev = '\n';: 프로그램이 시작될 때, prev를 줄바꿈 문자(\n)로 초기화. 이것은 나중에 불완전한 줄을 식별하는 데 사용된다.
메인 루프 - 문자, 단어, 줄 수 세기
while ((c = getchar()) != STOP)
{
n_chars++; // 문자를 카운트한다
if (c == '\n')
n_lines++; // 라인을 카운트한다
if (!isspace(c) && !inword)
{
inword = true; // 새 단어를 시작한다
n_words++; // 단어를 카운트한다
}
if (isspace(c) && inword)
inword = false; // 단어의 끝에 도달한다
prev = c; // 문자의 값을 보관한다
}
- while ((c = getchar()) != STOP): getchar() 함수는 사용자로부터 한 문자를 입력받는다. 입력된 문자가 |가 아닌 동안 반복
- 예를 들어, 사용자가 "Hello, World!"라고 입력하면 c는 하나씩 문자를 받아서 처리한다.
- n_chars++: 문자가 입력될 때마다 n_chars 값을 1씩 증가시켜 전체 문자의 수를 센다.
- if (c == '\n') n_lines++;: 줄바꿈 문자인 \n을 만나면 줄(라인)의 수를 1 증가시킨다.
- if (!isspace(c) && !inword): 현재 문자가 공백 문자(isspace(c) 함수는 공백, 탭, 줄바꿈 등을 확인)도 아니고, 단어 안에 있지 않다면 (inword가 false일 때),
- inword = true;로 설정하여 새로운 단어가 시작되었음을 표시.
- n_words++;: 새로운 단어를 만났으므로 단어의 수를 1 증가시킨다.
- if (isspace(c) && inword) inword = false;: 현재 문자가 공백이고, 단어 안에 있었다면(inword가 true), 단어가 끝났음을 표시하기 위해 inword를 false로 설정한다.
- prev = c;: 현재 문자를 prev에 저장하여, 다음에 입력되는 문자와 비교할 수 있게 한다.
불완전 라인 처리
if (prev != '\n')
p_lines = 1;
- if (prev != '\n'): 마지막 문자가 줄바꿈 문자가 아니면, 불완전한 줄이 존재하는 것으로 간주하고 p_lines를 1로 설정한다. 이는 마지막 줄이 줄바꿈 없이 끝났을 때를 의미.
결과 출력
printf("문자 수 = %ld, 단어 수 = %d, 라인 수 = %d,", n_chars, n_words, n_lines);
printf(" 불완전 라인 수 = %d\n", p_lines);
- 이 부분은 모든 카운팅 결과를 출력한다.
- 문자 수(n_chars), 단어 수(n_words), 줄 수(n_lines), 불완전 라인 수(p_lines)를 출력.
요약
- 이 프로그램은 사용자가 입력한 텍스트를 분석하여 문자 수, 단어 수, 라인 수를 센다.
- 텍스트 입력은 | 문자를 입력할 때까지 계속된다.
- 프로그램은 입력된 텍스트의 마지막 줄이 줄바꿈 문자 없이 끝났는지(불완전한 줄)를 확인.
- 최종적으로 각 통계를 화면에 출력.
리스트 7.8 paint.c 프로그램
// paint.c -- 조건 연산자를 사용한다
#include<stdio.h>
#define COVERAGE 350 // 페인트 한 통으로 칠할 수 있는 평방비트
int main(void)
{
int sq_feet;
int cans;
printf("페인트로 칠할 면적을 평방피트 단위로 입력하시오:\n");
while (scanf("%d", &sq_feet) == 1)
{
cans = sq_feet / COVERAGE;
cans += (sq_feet % COVERAGE == 0) ? 0 : 1;
printf("페인트 %d통(%s)을 구입해야한다.\n",cans,cans ==1 ? "can" : "cans");
printf("다음 값을 입력하시오(끝내려면q):\n");
}
return 0;
}
<코드분석>
내 평방피트가 페인트가 몇통이 필요한지 계산하는 프로그램이다.
조건연산자
? : |
<예제> (5 > 3) ? 1 : 2 는 값 1을 가진다. (3 > 5) ? 1 : 2 는 값 2를 가진다. (a > b) ? a : b 는 a와 b 둘 중 큰 값을 가진다. |
리스트 7.9 skippart.c 프로그램
// skippart.c -- continue를 사용하여 루프의 일부를 건너뛴다.
#include<stdio.h>
int main(void)
{
const float MIN = 0.0f;
const float MAX = 100.0f;
float score;
float total = 0.0f;
int n = 0;
float min = MAX;
float max = MIN;
printf("첫 번째 스코어를 입력하시오(끝내려면 q): ");
while (scanf("%f",&score)== 1)
{
if(score < MIN || score > MAX)
{
printf("%0.1f: 유효한 값이아닙니다 .다시 입력하세요.\n",score);
continue; // while 루프 테스트 조건으로 점프한다.
}
printf("%0.1f: 유효한 값입니다.\n",score);
min = (score < min) ? score : min;
max = (score > max) ? score : max;
total += score;
n++;
printf("다음 스코어를 입력하시오(끝내려면q): ");
}
if (n > 0)
{
printf("스코어 %d개의 평균은 %0.1f입니다.\n",n,total / n);
printf("최저 = %0.1f, 최고= %0.1f\n",min,max);
}
else
printf("유효한 값을 전혀 입력하지 않았습니다.\n");
return 0;
}
continue를 쓰면 루프를 건너 뛴다.
리스트 7.10 break.c 프로그램
// break.c -- 루프를 벗어나기 위해 break를 사용한다.
#include<stdio.h>
int main(void)
{
float length,width;
printf("사각형의 길이를 입력하시오:\n");
while (scanf("%f",&length) == 1)
{
printf("길이 = %0.2f:\n",length);
printf("너비를 입력하시오:\n");
if(scanf("%f",&width)!= 1)
break;
printf("너비 = %0.2f:\n",width);
printf("넓이 = %0.2f:\n",length * width);
printf("사각형의 길이를 입력하시오:\n");
}
printf("종료\n");
return 0;
}
강제로 if문이나 while문을 종료하고싶으면 break를 쓰면 된다.
리스트 7.11 animals.c 프로그램
// animals.c -- switch문을 사용한다
#include<stdio.h>
#include<ctype.h>
int main(void)
{
char ch;
printf("알파벳 글자를 입력하시오.");
printf("그러면 내가 \n그 글자로 시작하는 동물 이름을 하나 대겠습니다.");
printf("글자를 하나 입력하시오(끝내려면 #):\n");
while ((ch = getchar()) != '#')
{
if('\n' == ch)
continue;
if(islower(ch))
switch (ch)
{
case 'a':
printf("argali,아시아의 야생 양\n");
break;
case 'b':
printf("babirusa,말레이 반도의 야생돼지\n");
break;
case 'c':
printf("coati,미국 너구리\n");
break;
case 'd':
printf("desman,물에 사는, 두더지 비슷한 동물\n");
break;
case 'e':
printf("echidna,바늘두더지\n");
break;
case 'f':
printf("fisher,갈색을 띈 담비\n");
break;
default:
printf("에이, 너무 어렵다!\n");
}
else
printf("나는 소문자만 알아듣는다.\n");
while (getchar() != '\n')
continue; // 입력 라인의 나머지를 건너뛴다
printf("다른 글자를 하나 입력하시오(끝내려면 #): \n");
} // while 루프의 끝
printf("안녕\n");
return 0;
}
<코드 분석>
이건 switch 문을 사용해서 a,b,c,d,e,f,를 누르면 그단어로 시작하는 단어를 출력하는 프로그램이다.
switch 문을 사용할땐 break를 사용하는걸 잊지말자.
리스트 7.12 vowels.c 프로그램
// vowels.c -- 한 문장에 다수의 레이블을 사용한다
#include <stdio.h>
int main(void)
{
char ch;
int a_ct, e_ct, i_ct, o_ct, u_ct;
a_ct = e_ct = i_ct = o_ct = u_ct = 0;
printf("간단한 영문 텍스트를 입력하시오(끝내려면 #):\n");
while ((ch = getchar()) != '#')
{
switch (ch)
{
case 'a' :
case 'A' : a_ct++;
break;
case 'e' :
case 'E' : e_ct++;
break;
case 'i' :
case 'I' : i_ct++;
break;
case 'o' :
case 'O' : o_ct++;
break;
case 'u' :
case 'U' : u_ct++;
break;
default : break;
} // switch의 끝
} // while문의 끝
printf("number of vowels: A E I O U\n");
printf(" %4d %4d %4d %4d %4d\n",
a_ct, e_ct, i_ct, o_ct, u_ct);
return 0;
}
<코드분석>
a e i o u
A E I O U
사용자에게 문자를 받아 위에 해당되는 글자가 있으면 각 변수에 더한뒤 출력한다.
'스터디 > C언어' 카테고리의 다른 글
챕터 10 배열과 포인터 (0) | 2024.08.12 |
---|---|
챕터 9 함수 (0) | 2024.08.10 |
챕터 6 C의 제어문: 루프 (0) | 2024.08.09 |
챕터 5 연산자, 표현식, 문장 (0) | 2024.08.08 |
챕터 4 문자열과 입출력 포맷 (0) | 2024.08.07 |