코딩일지(2023-01-04)
내일은 중간고사이다.
어제랑 오늘 있을 실습과제를 해결해야 한다. 그리고 pdf에 있는 예제코드도 오늘 다 돌려보자. 그리고 1월2일에 있었던 실습문제 중, 버블정렬을 이용한 실습문제가 있었는데, 처음에 조금 헤맸었다. 한번 더 복습하자.
[C]실습 8-2
이번 코드를 짤떄 한가지 흥미로웠던 것은 배수 처리
이다. 무슨 말이나면, nxn정방행렬꼴로 값을 1부터 채워나가야 하는 형국인데,
언제 줄바꿈을 해줄거냐가 관건이었다(그냥 1부터 4까지, 1부터 9까지 나열하는 건 for문에서 n*n해주면 끝나는 거기 때문에 큰 문제가 되지 않는다.)
한가지 특이한것은 2를 입력후 2의 배수에서 줄바꿈이 일어난다는 것이었다.
그래서 처음에 다음과 같이 생각했다.
if ((i % n)==0)
{
printf("\n");
}
물론 이것도 된다. 근데 다름사람들이 짠코드를 보면 ==도 쓰지 않고 참과 거짓을 나누는 방식을 선호한다. 나도 그게 좀더 수준높은 코드 처럼보인다. 무슨 말이냐면, 이렇게 짜자는 것이다.
if (!(i % n))
{
printf("\n");
}
만약 i를 1부터 3까지라고 하고, n을 2라고 해보자.
i=1 -> !(1)==>false
i=2 -> !(0)==>true
i=3 -> !(1)==>false
이처럼 위 구문을 외워두면 편하게 쓸수있고, 공간복잡도와 시간복잡도 측면에서도 쪼끔? 더 효율적이라 볼 수 있다. 전체코드는 다음과 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
int n;
scanf("%d", &n);
for(int i = 1; i <= n*n; i++)
{
printf("%d ", i);
if (!(i % n))
{
printf("\n");
}
}
return 0;
}
[C]실습 8-4
다음의 참조코드를 만들어서 CI시키면 될 것 같다.
1)’!’가 들어왔는지 판단하는 코드, 느낌표가 들어왔으면 바로 break
걸어버리면 될 것 같다.
2)switch문 써서 case에서 연산자 판단하는 코드, 핀연산자 두개 검출하고, 연산자 하나 검출하자.만약 --
처럼 연산자가 두개 기입되면 첫번째 것만 연산자로 취급하자.
첫번쨰 참고코드
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void) {
char str[100];
scanf("%s", str);
if (strstr(str, "a") != NULL) {
printf("a 포함");
}
else {
printf("미포함");
}
return 0;
}
두번쨰 참고코드
이를 위해 한번 더 코드를 쪼개서 봐야 한다. 일단 “4/2”가 입력되었을때 4와2를 나눠서 담당하는 코드를 적어주자.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
int main(void) {
char str[] = "4/2";
char* ptr = strtok(str, "+-*/ ");
while (ptr != NULL)
{
printf("%s ", ptr);
Sleep(1000);
ptr = strtok(NULL, "+-*/ ");
}
return 0;
}
일단 8-4번 문제는 패스하고 9-1번부터 풀면은,
[C]실습 9-1
위 문제는 구글링으로 풀었다. 유클리드 호제법을 이용해야만 풀수가 있는데, 로직은 다음과 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 함수 원형 선언
int findGCD(int a, int b);
int main() {
// 두 수 입력
int num1, num2;
scanf("%d %d", &num1, &num2);
// 최대공약수 계산
int gcd = findGCD(num1, num2);
// 결과 출력
printf("%d\n", gcd);
return 0;
}
// 최대공약수를 찾는 함수
int findGCD(int a, int b) {
int temp;
// 유클리드 호제법을 사용하여 최대공약수 계산
while (b != 0) {
temp = b;
b = a % b;
a = temp;
}
return a;
}
유클리드 호제(Euclidian Algorithm)은 두 정수의 최대 공약수를 구하는 알고리즘 중 하나다.
[C]실습 9-2
생각한 논리는 단순하다.
5를 입력받으면 총 다섯개의 행이 생길꺼고, 0번쨰 행부터 4번째행까지 접근할 거다. 모든 행에 공통적으로 중앙에 별이 있다.
그리고 0번째 행에는 별이 중앙에 하나만 있지만, 1번쨰 행에는 별이 양옆에 한개씩 늘어나 있고, 2번째 행에는 별이 양옆에 두개씩 늘어나있게 된다.
일반화시키면, i번쩨 행에는 별이 양옆에 i개씩 늘어나있는 것을 볼수가 있다. 그리고 별입력후에는 별다른 공백을 넣지 않고 바로 줄바꿈 처리를 해준다.
따라서 i번째 행에서 0번째 열부터 중앙기준으로 i만큼 뺸 부분까지 공백을 반복하고, 이어서 별을 출력하면 될 것 같다. 로직은 다음과 같다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 함수 원형 선언
void printStar(int n);
int main() {
int n;
scanf("%d", &n);
printStar(n);
return 0;
}
void printStar(int n)
{
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n - i; j++)
{
printf(" ");
}
for (int k = n - i; k <= n + i; k++)
{
printf("*");
}
printf("\n");
}
}
[C]실습 9-3
최대공약수 논리(유클리드 호제)와 소수판별논리는 외워야 겠다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 함수 선언
int isPrime(int num);
int main() {
//정수입력
int x;
scanf("%d", &x);
//소수 여부 판별 및 결과 출력
printf("%s", isPrime(x) ? "prime" : "not prime");
return 0;
}
//소수 판별 함수
int isPrime(int x)
{
if (x < 2)
{
return 0;
}
for (int i = 2; i * i <= x; i++) {
if (x % i == 0) {
return 0; // 소수가 아님
}
}
return 1; // 소수임
}
참고코드> 최소공배수 구하는 코드
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 함수 선언
int findGCD(int num1, int num2);
int findLCM(int num1, int num2);
// 최소공배수 계산 함수
int findLCMBetweenRange(int start, int end, int n, int m) {
int lcm = n; // 초기값을 n으로 설정
for (int i = start; i <= end; i++) {
lcm = findLCM(lcm, i * m);
}
return lcm;
}
int main() {
// 변수 선언
int start, end, n, m;
// 네 개의 정수 입력 받기
printf("네 개의 정수를 입력하세요 (start end n m): ");
scanf("%d %d %d %d", &start, &end, &n, &m);
// 최소공배수 계산 및 출력
printf("%d부터 %d까지 %d과 %d의 최소공배수: %d\n", start, end, n, m, findLCMBetweenRange(start, end, n, m));
return 0;
}
// 최대공약수 계산 함수
int findGCD(int num1, int num2) {
while (num2 != 0) {
int temp = num2;
num2 = num1 % num2;
num1 = temp;
}
return num1;
}
// 최소공배수 계산 함수
int findLCM(int num1, int num2) {
return (num1 * num2) / findGCD(num1, num2);
}
[C]실습 8-4(이어서…)
좀 단순하게 풀어봤는데, 이게 정답이란다. 나는 처음에 띄어쓰기가 발생하는 경우에 대해서도 예외처리를 할 수 있게 +,-,*,/이외에 다른 연산자가 다른순서에 들어온 경우에 대해도 대응할 수 있게 짜려다보니 머리가 많이 복잡해져서 본질을 잃은것 같다. 반성하자.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
char o;
int x, y;
int result = 0;
while (1)
{
scanf("%d%c%d", &x, &o, &y);
if (o == '!')
{
return 0;
}
switch (o) {
case '+':
printf("%d%c%d=%d\n", x, o, y, x + y);
break;
case '-':
printf("%d%c%d=%d\n", x, o, y, x - y);
break;
case '*':
printf("%d%c%d=%d\n", x, o, y, x * y);
break;
case '/':
if (y == 0)
{
printf("Error\n");
break;
}
printf("%d%c%d=%.2f\n", x, o, y, (float)x / y);
break;
case '%':
printf("%d%c%d=%d\n", x, o, y, x % y);
break;
}
}
return 0;
}
참고/출처:https://enter.tistory.com/48
[C]실습 9-4(이어서…)
개인적으로 이게 푸는데 제일 오래 걸렸다. (하,,, 부끄럽다.. 반성하고 앞으로 코테연습도 열심히 해야겠다)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
// 함수 선언
int sumMultiple(int start, int end, int x);
int sum(int start, int end);
int sum_lcm(int start, int end, int lcm);
int findGCD(int a, int b);
int findLCM(int a, int b);
int main() {
// 사용자로부터 네 개의 정수 입력 받기
int start, end, n, m;
printf("네 개의 정수를 입력하세요 (start end n m): ");
scanf("%d %d %d %d", &start, &end, &n, &m);
int lcm = findLCM(n, m);
// 각각의 값을 계산하고 출력
printf("%d 이상 %d 미만의 %d의 배수의 합: %d\n", start, end, n, sumMultiple(start, end, n));
printf("%d 이상 %d 미만의 %d의 배수의 합: %d\n", start, end, m, sumMultiple(start, end, m));
printf("%d 이상 %d 미만의 %d의 배수이면서 %d의 배수인 수의 합: %d\n", start, end, n, m, sum_lcm(start, end, lcm)); //공배수(최소공배수부터!)
printf("%d 이상 %d 미만의 %d의 배수이거나 %d의 배수인 수의 합: %d\n", start, end, n, m, sumMultiple(start, end, n) + sumMultiple(start, end, m)- sum_lcm(start, end, lcm));
printf("%d 이상 %d 미만의 %d의 배수이면서 %d의 배수가 아닌 수의 합: %d\n", start, end, n, m, sumMultiple(start, end, m) - sum_lcm(start, end, lcm));
printf("%d 이상 %d 미만의 %d의 배수도 %d의 배수도 아닌 수의 합: %d\n", start, end, n, m, sum(start, end) - sumMultiple(start, end, n) - sumMultiple(start, end, m) + sum_lcm(start, end, lcm));
return 0;
}
// start 이상 end 미만의 x의 배수의 합을 계산하는 함수
int sumMultiple(int start, int end, int x) {
int sum = 0;
for (int i = start; i < end; i++) {
if (i % x == 0) {
sum += i;
}
}
return sum;
}
int sum(int start, int end) {
int sum = 0;
for (int i = start; i < end ; i++) {
sum += i;
}
return sum;
}
// 최대공약수 계산 함수
int findGCD(int a, int b) {
while (b != 0) {
int temp = b;
b = a % b;
a = temp;
}
return a;
}
// 최소공배수 계산 함수
int findLCM(int a, int b) {
// 두 수의 곱을 최대공약수로 나누어 계산
int gcd = findGCD(a, b);
int lcm = (a * b) / gcd;
return lcm;
}
int sum_lcm(int start, int end, int lcm) {
int sum_lcm = 0;
for (int i = 0; i < 20; i++) {
if (start <= lcm*i&& lcm * i < end) {
sum_lcm += lcm * i;
}
}
return sum_lcm;
}
[C]연습문제 - 1
위 문제를 해결할 떄 다음과 같이 해결했다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int numbers[5];
int sum = 0;
int cnt = 0;
// 사용자로부터 5개의 정수 입력 받기
for (int i = 0; i < 5; i++) {
scanf("%d", &numbers[i]);
if (numbers[i] > 0) {
sum += numbers[i];
cnt++;
}
}
// 평균 계산 및 출력
if (cnt > 0) {
printf("avg = %.2f", (float)sum / cnt);
} else {
printf("입력된 양수가 없습니다.");
}
return 0;
}
근데 한가지 의문이 들었다. 그냥 배열을 않쓰고 temp하나 중간에 두고 쓰면 되지 않겠냐고 말이다. (아래와 같이)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int cnt=0, sum = 0,temp;
for (int i = 0; i < 5; i++)
{
scanf("%d", &temp);
if (temp > 0)
{
sum += temp;
cnt++;
}
}
printf("avg = %.2f\n", (float)sum / cnt);
return 0;
}
이렇게 하면 이전코드의 정수형 배열처럼 따로 값을 저장하는 일이 없어지기 때문에 메모리 절약 측면에서 이득이 아닐까하는 생각이 들었다.
[C]연습문제 - 2
쉽다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int n,max=-100,min=100,cnt=0,sum=0;
while (1) {
scanf("%d",&n);
if (n == 0) {
break;
}
sum += n;
cnt++;
max = (max < n) ? n : max;
min = (min > n) ? n : min;
}
printf("Avg = %.2f, Min = %d, Max = %d\n", (float)sum/cnt, min, max);
return 0;
}
근데 최근에 if(n==0)
마저도 어떻게 줄일 수 없을까 했는데,
(n == 0) ? break : 0;
이렇게는 안된다고 한다. break도 명령어라 될줄 알았는데, 이상하게 안된다더라ㅅㅂ
디버거에서는 “식”이 필요하다느니 ‘;’가 필요하다느니ㄷㄷ 암튼 chatGPT도 안된다고 했으니 정말 안되는것 같다.
[C]연습문제 - 3
참조코드를 나눈다음 합쳐야겠다.
1)for문과 ‘A’만을 써서 알파벳 나열
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
for (int i = 0; i < 6; i++)
{
printf("%c\n", 'A' + i);
}
return 0;
}
2)값을 입력받고 2i-1까지 행 출력,공백개수랑 문자개수 확인
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int n = 0;
int i;
scanf("%d", &n);
for (i = 0; i < n; i++)
{
printf("공백: %d\n", n - (i+1));
printf("문자: %d\n", i+1);
printf("%c\n", 'A' + i);
}
for (int i = 0; i < n - 1; i++)
{
printf("문자: %d\n", i + 1);
printf("공백: %d\n", n - (i + 1));
printf("%c\n",'A'+n-1-(i+1));
}
return 0;
}
3)CI
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int n = 0;
int i;
int j;
scanf("%d", &n);
for (i = 0; i < n; i++)
{
for (j = 0; j < n - (i + 1); j++)
{
printf(" ");
}
for (j = 0; j < i + 1; j++)
{
printf("%c", 'A' + i);
}
printf("\n");
}
for (int i = 0; i < n - 1; i++)
{
for (j = 0; j < i + 1; j++)
{
printf(" ");
}
for (j = 0; j < n - (i + 1); j++)
{
printf("%c", 'A' +(n-1)-(i+1));
}
printf("\n");
}
return 0;
}
[C]연습문제 - 4
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int A[5];
int B[5];
int ans[10];
int i;
int j = 0;
int k = 5;
for (i = 0; i < 5; i++)
scanf("%d", &A[i]);
for (i = 0; i < 5; i++)
scanf("%d", &B[i]);
for (i = 0; i < 5; i++)
ans[i] = A[i];
for (j = 0; j < 5; j++)
{
for (i = 0; i < 5; i++)
{
if (B[j] == A[i])
{
break;
}
ans[k] = B[j];
k++;
}
}
for (i = 0; i < k; i++)
printf("%d ", ans[i]);
return 0;
}
위 코드에서는 두 정수형 배열에 값을 입력후, 다음과 같은 이슈가 발생했다.
챗GPT한테 물어봐도, ‘ans’배열에 값을 저장하는 부분이 중첩된 반복문 안에 있어서 중복된 값이 ans에 계속 쌓이게 되면서 결국 ans배열의 사이즈가 10인데 이를 넘어서서 값을 저장하려는 시도가 생기게 되고 그래서 오버플로우가 발생했기 떄문이란다.
그래서 다음과 같이 플래그 변수, ‘fnd’를 설정해주었다.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main() {
int A[5];
int B[5];
int ans[50];
int i;
int j = 0;
int k = 5;
for (i = 0; i < 5; i++)
scanf("%d", &A[i]);
printf("next\n\n");
for (i = 0; i < 5; i++)
scanf("%d", &B[i]);
for (i = 0; i < 5; i++)
{
ans[i] = A[i];
}
for (j = 0; j < 5; j++)
{
int fnd = 0;
for (i = 0; i < 5; i++)
{
if (B[j] == A[i])
{
fnd = 1;
break;
}
}
if (!fnd) {
ans[k] = B[j];
k++;
}
}
for (i = 0; i < k; i++)
{
printf("%d ", ans[i]);
}
return 0;
}
댓글남기기