윤성우의 열혈 C프로그래밍 - 도전! 프로그래밍 1

Yumin Jung·2023년 5월 9일
1
post-thumbnail

다짜고짜 C언어를 하기 시작했다. (이유?: 추후 공개) 포인터 이전까지는 회독을 많이 한 책이어서 이론 정리 없이 바로 도전 문제를 풀어본다.

도전 1 (o)

복습
23/07/15 (o)

#include <stdio.h>

int main(void)
{
int decimalToHexadecimal = 0;
  printf("16진수로 변환할 10진수 정수를 입력하세요: ");
  scanf("%d", &decimalToHexadecimal);
  printf("%x", decimalToHexadecimal);

  return 0;
}

괜찮은 변수명을 정하기 위해 인터넷 서칭 후 정했다. 근데 좀 긴 것 같다. 줄여보겠다.
컴파일러는 왜 온라인을 사용했냐면, 설치중이기 때문이다...... 도전 2번부터는 VS 2022를 사용하도록 하겠다.

도전 2 (x)

복습
23/07/15 (o)

#include <stdio.h>

void Gugudan(int num1, int num2) {
	int n = 1;

	while (num1 > num2) {
		while (n < 10) {
			printf("%d * %d = %d\n", num1, n, num1*n);
			n++;
		}
		num1--;
	}
	while (num1 == num2) {
		while (n < 10) {
			printf("%d * %d = %d\n", num1, n, num1 * n);
			n++;
		}
	}
	while (num1<num2)
		while (n < 10) {
			printf("%d * %d = %d\n", num2, n, num2 * n);
			n++;
		}
		num2--;
	}

	int main(void) {
		int n1, n2;
		printf("구구단 푸는 프로그램입니다. 순서는 자유로우니 2가지 정수를 써서 범위를 나타내세요: ");
		scanf_s("%d %d", &n1, &n2);
		Gugudan(n1, n2);
	}

위의 코드는 망했다. 풀지 못하였다. 두 정수를 입력 받아 그 사이에 있는 단 수까지 구구단이 실행되어야 하는 부분에서 어려움을 느꼈다.

#include <stdio.h>

void NineNine(int num1, int num2);	

int main(void)
{
	int num1, num2;

	printf("두개의 정수 입력 : ");
	scanf("%d %d", &num1, &num2);

	if(num1<num2)
		NineNine(num1, num2);
	else
		NineNine(num2, num1);

    return 0;
}

/* num1단부터 num2단까지 출력 */
void NineNine(int num1, int num2)	
{
	int i;
	
	while(num1<=num2)
	{
		for(i=1; i<10; i++)
			printf("%d * %d = %d \n", num1, i, num1*i);
		printf("\n");
		num1++;
	}
}

정답 코드를 보면 나와 다르게 한꺼번에 하려고 하지 않고, 메인함수에서 큰 것과 작은 것을 미리 구분짓게 만들었고, 그렇게 하여 인자를 전송해 쉽게 풀어냈다. 함수를 이용하여 더 쉽게 풀어내도록 코딩을 하기 전에 생각하는 연습을 해야겠다.
함수로 기능을 만든다.

도전 3 (x)

복습
23/07/18 (o)

#include <stdio.h>

void TwoIntGCD(int, int);

int main(void) {
	int n1, n2;
	printf("두 개의 정수를 입력하면 최대공약수를 구해주겠다: ");
	scanf_s("%d %d", &n1, &n2);
	TwoIntGCD(n1, n2);

}

void TwoIntGCD(int num1, int num2) {
	int n;
	for (n = 0; (n<=num1)&&(n<=num2); n++) {
		if (num1 % n == num2 % n) {
			printf("%d", n);
		}
	}
}

또한 망한 코드이다. 어떻게든 구현해보려 했지만 개념이 제대로 잡히지 않은 듯하다.

이 문제의 풀이 방법은 인터넷으로 검색했을 때 다양한 많은 방법이 있었다.

#include <stdio.h>

int main(void)
{
    int a, b;
    int i;
    
    printf("정수 2개 입력: ");
    scanf("%d %d", &a, &b);
    
    if (a > b)
    {
        for (i = a; i > 0; i--)
            if (a % i == 0 & b % i == 0)
                break;
    }
    else
    {
        for (i = b; i > 0; i--)
            if (a % i == 0 & b % i == 0)
                break;
    }
    
    printf("%d와 %d의 최대공약수: %d \n", a, b, i);
    
    return 0;
}

받은 두 정수 중 큰 정수를 하나씩 빼는식으로 반복문을 돌리는데, 나눴을 때 두 개다 0이 나오는 가장 큰 수를 최대공약수로 나타낼 수 있다.

🤫위는 잘못된 코드이다! 복습을 하는 중 발견하였다. &는 논리연산자가 아닌 비트연산자이다.

#include <stdio.h>

void GCD(int num1, int num2);

int main(void) {
	int num1, num2;
	printf("최대공약수를 만들 두 수를 입력하세요: ");
	scanf_s("%d %d", &num1, &num2);
	GCD(num1, num2);
	return 0;
}

void GCD(int num1, int num2) {
	/*1. 최대공약수로 두 수를 어떻게든 나눠도 0이다.*/
	//2. 최대공약수는 두 수보다 클 수 없다.
	int a;

	if (num1 > num2) {
		for (a = num1; a > 0; a--)
			if ((num1 % a == 0) && (num2 % a == 0))
				break;
	}

	else {
		for (a = num2; a > 0; a--)
			if ((num1 % a == 0) && (num2 % a == 0))
				break;
	}
	printf("최대공약수: %d", a);
}

도전 4 (x)

복습
23/07/18 (o)

접근은 좋았다. 중첩 반복문으로 x가 1일때 / x가 1이고 y가 1일때 ~ 이런식으로 쭉 반복하여 결과를 나타내려는 시도(고민)은 정말 잘했다고 본다. 하지만 조건식 (for문의 초기식;조건식;증감식 중에서) 이 문제였다. 어떻게 하면 조건을 정말 잘 걸었다고 소문이 날까 고민했지만 돈을 빵가격으로 나눈 것이 빵을 최대로 살 수 있는 개수라고는 생각도 못하였다.

#include<stdio.h>

const int BREAD=500;
const int SNACK=700;
const int DRINK=400;

int main(void)
{
	int i, j, k;
	int money;
	printf("현재 당신이 소유하고 있는 금액 : ");
	scanf("%d", &money);

	for(i=1; i<money/BREAD; i++)
	{
		for(j=1; j<money/SNACK; j++)
		{
			for(k=1; k<money/DRINK; k++)
			{
				if(money==BREAD*i+SNACK*j+DRINK*k)
				{
					printf("크림빵 %d개, ", i);
					printf("새우깡 %d개, ", j);
					printf("콜  라 %d개 \n", k);
				}
			}
		}
	}

	printf("어떻게 구입하시겠습니까? \n");
	return 0;
}

그리고 const int(변하지 않는 상수)는 나중에 배우는 것인데 풀이에는 적용돼있었다. 나중에 const 선언 관련에 대해 배우고 다시 한 번 복습해보겠다.

도전 5 (x)

도전 1번 이후로 하나도 제대로 맞춘게 없다. 도전 5는 잘 풀었다고 생각했는데 답이 제대로 나오지 않았다.

#include <stdio.h>

int main(void) {
	int a;
	int num;
	for (num = 1; num < 30; num++) {
		for (a = 1; a <= num; a++) {
			if (num / a == num && num / a == 1)
				printf("%d ", num);
		}
	}
}

뭐가 틀렸을까 ?
10개의 소수를 출력하기 위해 (2 3 5 7 11 13 17 19 23 29) for문의 num을 29까지 증가하도록 시켰다. 그리고 a로 나누는데 a의 값을 num보다 작거나 같게 설정하고, num / a == num 일때와 num / a == 1일 때와...............
아 잠시만
방법을 알았다. 다시 풀고 오겠다.
.
.
.
모르겠다. 근데, 저 풀이가 왜 틀렸는지는 알았다. 저 두 개의 조건을 만족하는건 1에서 29개의 숫자 전부 다이기 때문이다. 그래서 그것만 제외하는 방법을 구현하지 못한것이다. 어떻게 하는 것일까. 온갖 조건연산자를 갖다 붙혀봤다. 하지만 답은 계속 나오지 않았다..

#include<stdio.h>

int IsPrime(int n);

int main(void)
{
	int i=2, cnt=0;

	while(cnt!=10)
	{
		if(IsPrime(i)==1)
		{
			printf("%d ", i);
			cnt++;
		}
		i++;
	}
	return 0;
}

int IsPrime(int n)	   // 소수면 true(1) 리턴
{
	int divisors=0, i;
	
	for(i=1; i<=n; i++)
	{
		if(n%i==0)
			divisors++;
	}
	if(diverse)
	if(divisors==2)
		return 1;

	return 0;
}

위는 답
하. 머리 아파서 내일


2023-07-21 다시 돌아왔다.

#include <stdio.h>

int main(void) {
	int num = 2;
	int i;
	for (i = 1; i <= num; i++) {
		if ((num / i) != (1 && num))
			num++;

		else {
			printf("%d ", num);
				num++;
		}
	}
	return 0;
}

풀이를 하지 않고 까먹고 지나갔다보니, 다시 풀어도 여전히 틀렸다.

다시 한 번 정답을 보겠다.

#include<stdio.h>

int IsPrime(int n);

int main(void)
{
	int i=2, cnt=0;

	while(cnt!=10)
	{
		if(IsPrime(i)==1)
		{
			printf("%d ", i);
			cnt++;
		}
		i++;
	}
	return 0;
}

int IsPrime(int n)	   // 소수면 true(1) 리턴
{
	int divisors=0, i;
	
	for(i=1; i<=n; i++)
	{
		if(n%i==0)
			divisors++;
	}
	if(divisors==2)
		return 1;

	return 0;
}

while문으로 개수를 세는 용도로 변수 cnt를 만들어줬고,
Isprime 함수 리턴값으로 1을 받으면 입력하고 카운트가 세지는 알고리즘이다.

IsPrime 함수를 분석해보겠다. 이 함수는 소수 판독기이다.
소수면 1을 리턴하는 알고리즘인데, for문에서 나머지가 0이 나오는 개수 누적을 divisors에 한다.
정수가 1과 자기자신으로 밖에 나누어지지 않는다는 것은 나누어지는 횟수는 2번이라는 의미이다.

이 divisors의 나머지가 2개이면 소수이므로 1을 리턴 한다.

대단하다. 재밌는 로직이다. 카운트를 세는 원리를 잘 기억해야겠다.

👀👀복습요망

도전 6 (o)

#include <stdio.h>

int main(void) {
	int h=0,m,s,a,remain=0;
	printf("초를 입력하시오 : ");
	scanf_s("%d", &a);

	if (a >= 3600) {
		h = a / 3600;
		remain = a % 3600;
		if (remain >= 60) {
			m = remain / 60;
			s = remain % 60;
		}
		else {
			m = 0;
			s = remain;
		}
	}
	else
		if (remain >= 60) {
			m = remain / 60;
			s = remain % 60;
		}
		else {
			m = 0;
			s = remain;
		}
	printf("[h:%d / m:%d / s:%d]", h, m, s);

	return 0;
}

꾸역꾸역 해냈다. 완전 노가다 식으로 한 것 같은데 이렇게 장기간 고민해서 노가다로 성공하면 의미가 있는건지 걱정된다. 실력이 느는 것인가.

답지를 꺼내 비교해보겠다.

#include<stdio.h>

const int H=60*60;
const int M=60;

void SecondToHMS(int sec);

int main(void)
{
	int sec;

	printf("초(second) 입력 : ");
	scanf("%d", &sec);
	SecondToHMS(sec);

	return 0;
}

void SecondToHMS(int sec)
{
	int h, m, s;
	
	/*시 구하기 */
	h=sec/H;
	sec=sec%H;

	/*분 구하기 */
	m=sec/M;
	sec=sec%M;

	/*초 구하기 */
	s=sec;

	printf("[h:%d, m:%d, s:%d] \n", h, m, s);
}

내 코드는 딱 봐도 너무 복잡하게 생각한 티가 난다.
분(m)이 0이 되었을 때의 상황을 고려하다보니, 조건문까지 나왔다. 하지만 다시 생각해보면, 분이 0분이 나오더라도 60으로 나눴을때 나머지가 초가 되는 것이다.

함수를 이용해 더 깔끔하게 정리하는 연습을 해야겠다.

도전 7

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int Square(int b) {
	int a = 0;
	a = 2 * (2 * (b - 1));
	return a;
}

int main(void)
{
	int k = 2;
	int n;
	printf("상수 n 입력: ");
	scanf("%d", &n);

	while (Square(k) < n) {

	}
	

	printf("공식을 만족하는 k의 최댓값은 %d", k);
	return 0;
}

정답을 확신하고 결과를 냈지만, 틀리게 나왔다.
일단은 거듭제곱을 대신하는 저 공식이 틀렸다.

재도전!

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int Square(int b) { //2의 거듭제곱 구하는 함수
	if (b == 1) 
		return 2;
	else
		return (2 * Square(b-1));
	
}

int main(void)
{
	int k=1;
	int n;
	printf("상수 n 입력: ");
	scanf("%d", &n);

	while (Square(k) <= n)//거듭제곱이 n보다 작거나 같을 때 동안
		k++;

	printf("공식을 만족하는 k의 최댓값은 %d", k-1);
	return 0;
}

이 문제는 풀지 못하다가 문제 8번을 보고 힌트를 얻었다. 2의 n승을 구하는 함수를 재귀적으로 구현하였다. 8번을 동시에 풀어버렸다.
답지를 한 번 살펴보겠다.

#include <stdio.h>

int main(void)
{	
	int n, k;
	int inc=1;

	printf("상수 n 입력 : ");
	scanf("%d", &n);
	
	if(n==0)
	{
		printf("만족하는 k 없음 \n");
		return 0;
	}
	
	for(k=0; inc*2<=n ; k++) // 무한루프
	{
		inc=inc*2;
	}

	printf("공식을 만족하는 k : %d \n", k);	
	return 0;
}

이걸 구현하지 못했다.

inc=inc*2;

말 아낀다...

profile
문과를 정말로 존중해

0개의 댓글