#include <stdio.h>

 

int main(int argc, const char * argv[]) {

    int M, N;

    int rnum=2500;

    scanf("%d %d", &M, &N);

    

    char board[M][N+1];

    for(int i=0; i<M; i++)

        scanf("%s", board[i]);

// borad 판 생성, 입력 완료!!!

    for(int stepy = 0; stepy < (M-7); stepy++) { // stepx, stepy의 좌표는 8*8 보드의 첫 시작점

        for(int stepx = 0; stepx < (N-7); stepx++) {

    

            int bcount = 0; // 첫블럭이 B일때 바꿔야 하는 수

            int wcount = 0; // 첫블럭이 W일때 바꿔야 하는 수

            int count;

// 검사

            for(int i=0; i<8; i++) { // i는 세로, j는 가로

                for(int j=0; j<8; j++) {

                    //첫 블럭이랑 색이 같은 것들 (홀수줄에 홀수 번째 칸, 짝수줄에 짝수번째 칸)

                    if((i%2 == 0 && j%2 == 0) || (i%2 == 1 && j%2 == 1)) {

                        if(board[stepy+i][stepx+j] == 'B') // 그 칸이 B라면

                            wcount++;

                        else if(board[stepy+i][stepx+j] == 'W')// 그 칸이 W라면

                            bcount++;

                    }else{ // 그 외

                        if(board[stepy+i][stepx+j] == 'B') // 그 칸이 B라면

                            bcount++;

                        else if(board[stepy+i][stepx+j] == 'W')// 그 칸이 W라면

                            wcount++;

                    }

                }

            }

            if(bcount > wcount)

                count = wcount;

            else

                count = bcount;

            if(count < rnum)

                rnum = count;

        }

        

    }

                        

                    

            

    printf("%d\n", rnum);

    return 0;

}

'IT공부 > beakjoon 알고리즘' 카테고리의 다른 글

객체지향프로그래밍_3  (0) 2022.03.13
1436번: 영화감독 숌  (0) 2022.03.13
7568번: 덩치  (0) 2022.03.08
2231번:분해합 문제  (0) 2022.03.06

Chapter.3 클래스

  • 객체지향 프로그래밍 개요
    • 객체란 변수들과 그와 관련된 메서드들이 모여서 이룬 하나의 꾸러미! ( 객체 = 동작이나 상태를 나타내는 단위 )
    • 클래스란 C의 구조체에서 확장된 변수, 함수를 포함한 하나의 틀 이다 ( 클래스 = 찍어내기 위한 틀 )
    • 인터페이스 함수 : 내부로 직접 접근 못하는 사용자를 대신하여 내부안에서 기능을 수행하게 해주는 함수
  • 클래스의 기본 문법
    • 클래스의 기본 형태
      • class 클래스 이름    {
      • 접근제어 지시자:    // public, private, protected
      •     맴버변수 선언;
      •     맴버함수 선언 및 정의;
      • };
    • 맴버 선언 및 정의
      • 클래스는 '생성자'를 이용해 초기화 할 수 있음! - 생성자의 특징
        1. 반환하는 자료형이 없다
        2. 호출하는 함수가 아니라 적절한 시기에 자동으로 호출되는 함수
      • '사용자가 객체를 선언하면 자동으로 호출됨!' -> 따라서 맴버가 자동으로 초기화 가능
      • 선언법 // 클래스와 같은 이름의 함수를 선언 해주면 됨 
        • class Ctest {
        • public:
        •     Ctest() { ~ }
        • }
      • 생성자 사용시 초기화 목록 이용하는 법 -> 생성자 선언 뒤 콜론: 입력후 변수(값) 의 형태로 입력한다
        • class CTest {
        • public:
        •     CTest() : m_nData(10), m_nData2(20) { ~ }
        • }
    • 접근제어 지시자
      • 클래스의 특정 요소에 사용자가 접근할 수 없게 하기 위해 활용한다
        1. public : 멤버에 관한 모든 외부 접근이 허용됩니다
        2. protected : 멤버에 관한 모든 외부 접근이 차단됩니다 단 상속 관계가 있는 파생 클래스에선 접근 허용
        3. private : 외부 접근, 파생 클래스 접근 차단, 별도의 접근제어 지시자가 없을때 private로 간주됨
      • 이때 생성자도 접근제어 지시자의 영향을 받는다 ( 별도의 목적이 없다면 생성자는 public 으로 설정하자 )
  • 생성자와 소멸자
    • 객체가 생성, 소멸될 때 '자동으로' 호출됨, 반환 형식이 없음, 함수와 이름이 같다(소멸자의 경우 ~함수이름() 이다)
    • 매개변수가 없는 생성자를 디폴트 생성자 라고 한다
    • 생성자와 소멸자를 기술하지 않으면 컴파일러가 알아서 디폴트 생성자와 소멸자를 넣어준다
    • 선언된 블록 범위가 끝나면 자동으로 소멸된다 ex) 메인에서 호출후, 메인이 끝나면 -> 소멸자가 실행된다
      • main() 함수가 호출되기 전에 생성자가 호출될 수 있다(전역 변수로 선언한 클래스의 경우)
      • 생성자는 다중 정의 할 수 있다 (오버로딩)
      • 소멸자는 다중 정의 할 수 없다
      • main() 함수가 끝난 후에 소멸자가 호출될 수 있다
      • 생성자와 소멸자는 생략할 수 있으나 생략할 경우 컴파일러가 디폴트 생성자와 소멸자를 만들어 넣는다
      • 새로운 생성자를 만들면 디폴트 생성자를 생략할 수 있다(컴파일러도 만들어 주지 않음)
    • 동적 객체의 생성과 소멸
      • C++에서 동적 객체의 생성과 소멸은 new 와 delete 이다
      • 이때 클래스를 동적 객체로 생성하면, new 실행시 생성자가, delete 실행시 소멸자가 실행된다
    • 참조 형식 멤버 초기화
      • 참조자는 반드시 선언과 동시에 초기화 해야한다!
      • 이때 생성자 초기화 목록을 이용해 초기화 해야 한다
        • ex) CTest(int &rParam) : m_nData(rParam) { }; // int &m_nData(참조형 맴버변수)
    • 생성자 다중 정의
      • 생성자는 다중 정의 할 수 있다
      • 이때 생성자 위임 이라는 편리한 기능을 사용할 수 있다 
        • ex) CMyPoint(int x) { ~ } / CMyPoint (int x, int y) :CMyPoint(x) { ~ }
        • 즉 생성자 CMyPoint 실행 시 생성자 CMyPoint(int x) 또한 추가로 호출 될 수 있도록 위임 한 것
    • 명시적 디폴트 생성자
      • 디폴트 생성자가 필요할 때 다중 정의를 해 놓으면 디폴트 생성자가 만들어 지지 않으므로, 일부러 명시 해 준다
      • ex) CTest(void) = default; // CTest() 라는 생성자는 디폴트 생성자 이다!
      • delete 로 생성자 함수를 삭제할 수도 있다 ex) CTest(void) = delete; // 디폴트 생성자 삭제
  • 메서드(Method)
    • 매서드 = 맴버 함수 = 인터페이스 함수 // 클래스가 제공하는 기능! 방법! 을 뜻한다
    • this 포인터
      • 작성중인 클래스의 실제 인스턴스에 대한 주소(본인)
종류 일반 상수화 정적 가상
관련 예약어 - const static virtual
this 포인터 접근 가능 가능 불가능 가능
일반 멤버 읽기 가능 가능 가능(제한적) 가능
일반 멤버 쓰기 가능 불가능 가능(제한적) 가능
적정 멤버 읽기 가능 가능 가능 가능
적정 멤버 쓰기 가능 불가능 가능 가능
특징 보편적인 메서드 멤버 쓰기 방지가 목적 C의 전역함수와 유사 상속 관계에서 의미
    • 상수형 메서드
      • 멤버 변수에 읽기 접근은 가능하지만 쓰기는 허용하지 않은 메서드
      • ex) int GetData() const { ~ } // 이렇게 함수의 원형 뒤에 const 만 선언해 주면 된다
    • 상수형 메서드의 예외사항
      • 상수화 된 메서드 로도 멤버변수에 접근할 수 있게 맴버변수 선언을 해준다
        • mutable int m_nData = 0; // mutable 선언으로 GetData
      • 상수형 참조를 일반 참조로 형변환 한다
        • const int &nParam 으로 입력받은 것을 int &nParam 으로 변경시킴
        • int &nNewParam = const_cast<int &>(nParam);
        • [ const_cast<새형식> (대상) ]
    • 멤버 함수 다중정의
      • 메서드 또한 다중정의 될 수 있다
      • 다중정의시 잘못된 실 인수가 들어오면 delete 로 과감히 삭제하자
        • ex) void GetIntData(double dParam) = delete; // double 형 실인수가 들어오면 소멸자 실행
    • 정적멤버
      • 정적 변수는 전역변수나 함수와 마찬가지, this 포인터 사용 불가
      • static 예약어로 사용 ex) static int GetCount(); / static int m_nCount; / int CTest::m_nCount = 0;
      • 이때 정적변수는 반드시 선언과 정의를 분리해야 한다
        • 원래 CTest a(5) 선언 후 a.GetCount(); 로 선언해야 하지만 그냥 GetCount(); 로 정적 멤버에 접근 가능하다

연습문제

1. 클래스 접근 제어 지시자 중에 private 이 의미하는 것은 무엇인가? = 외부, 상속 클래서에서 접근 불가

2. 클래스 인스턴스가 생성될 때 자동으로 호출되는 함수와 그 함수의 원형의 가장 큰 특징은? = 생성자, 반환형이 없다

3. 다음 코드에서 m_nData(nParam) 이 속한 부분을 무엇이라 부르는지 답하시오 = 초기화 목록

CTest(int nParam)

    : m_nData(nPatam) // 초기화 목록

{ ~ }

4. 다음 코드에서 잘못된 점과 개선방법 = 참조형 변수를 초기화 할때는 초기화 목록으로 초기화 해야 한다 CRefTest(int &rPatam) : m_nData(rParam) { ~ }

5. 메서드 함수 내부에서 실제 클래스 인스턴스의 주소를 가리키는 포인터는? = this

6. 상수형 메서드에서 할 수 없는 일은 무엇인지 답하세요 = 멤버변수 쓰기(읽기는 허용)

7. 정적 멤버에서는 '이것'을 사용할 수 없다. 이것은? = this 포인터

'IT공부 > 이것이 C++이다' 카테고리의 다른 글

객체의 관계 규정과 설계_1  (0) 2022.03.16
객체지향 프로그래밍_2  (0) 2022.03.12
C에서 C++ 문법 전환하기_2  (0) 2022.03.09
C 에서 C++로 문법 전환하기_1  (0) 2022.03.07

Chapter.2 C++ 함수와 네임스페이스

  • 디폴트 매개변수
    • C에서는 함수를 호출하려 한다면 매개변수의 실 인수를 기술해야한다
    • C++에서는 매개변수의 초깃값을 설정해서 입력이 없을 경우 초깃값을 대입해 준다
      • 따라서 호출자를 보고 함수의 원형을 확정하면 안됨!!
      • ex) int TestFunc(int nParam = 10) // = int TestFunc(int = 10) 
      • 이때 함수 원형의 선언 부분에 기술해야하고, 정의 부분에 기술하면 컴파일 오류가 발생한다 // 선언부분 변수 이름 생략 가능
    • 매개변수 선언시 규칙
      1. 피호출자 함수 매개변수의 디폴트 값은 반드시 오른쪽 매개변수 부터 기술해야 한다
      2. 매개변수가 여려 개일 때 왼쪽 첫번째 매개변수의 디폴트 값을 기술하려면 나머지 오를쪽 모든 매개변수에 대한 디폴트 값을 기술해야 하며, 절대로 중간에 빼먹으면 안된다!
      3. 호출자 함수가 피호출자 함수 매개변수의 실인수를 기술하면 이는 왼쪽부터 짝을 맞추어 적용되며, 짝이 맞지 않은경우 매개변수는 디폴트 값을 적용한다
    • 모호성을 조심할 것, 가급적 디폴트 매개변수 사용을 지양할 것
  • 함수의 다중 정의
    • 다중정의, Overloading 은 함수의 다형성을 지원(편의성, 확장성)
      • 함수의 구성 요소 = 반환형식 호출규칙 함수이름(매개변수, 매개변수 ...);
    • 이때 다중정의, 오버로딩을 하기 위해선 매개변수를 제외한 모든 것은 동일해야 한다!!
    • 다중정의의 모호성
      • 다중정의와 디폴트 매개변수가 조합되면 '모호성'이 발생할 수 있다
        • ex) void TestF(int a) { ~ } / void testF(int a, int b = 10) { } 
        • 이때 TestF(5); 를 선언한다면 컴파일 오류가 발생한다( 모호성 때문)
    • 함수 템플릿(template)
      • 오버로딩으로 여러 함수를 만들기 보다 템플릿으로 만드는 것이 더 효율적이다
      • 템플릿은 일종의 '틀' / 함수를 찍어내기 위한 
        • ex) template <typename T> / T TestFunc(T a) { } // T는 자료형
        • 이때 testFunc을 호출하는 매개변수(실인수)의 자료형에 따라 T가 정해진다!
    • 인라인 함수(inline)
      • 인라인 함수 = (함수의 장점 + 매크로(#define) 의 장점) 이다
      • 함수의 원형 앞에 inline 예약어만 작성하면 된다
        • ex) inline int TestFunc(int a) { ~ }
      • 코드가 일정 수준 이상으로 길어지면 인라인 함수보다 그냥 함수가 더 효율적
      • 이는 컴파일러가 판단하여 인라인함수 <-> 일반 함수 로 바꿔서 컴파일 할 수 있다
    • 네임스페이스(namespace)
      • C++가 지원하는 각종 요소들(변수, 함수, 클래스 등)을 한 범주로 묶어주기 위한 문법
      • 소속, 구역 등으로 이해 (이름의 성 같은 존재)
        • 네임스페이스 선언 : namespace 이름 { ~ } // ~ 안에 변수, 함수, 클래스 가 들어갈 수 있다
        • 네임스페이스의 중복 선언이 가능하다 
        • 네임스페이스가 없는 함수는 '전역 네임스페이스'에 속한다
      • using 선언
        • namespace를 생략하기 위한 예약어
          • using namespace std; // std::cin 이라고 호출해야 했던 함수를 cin 으로도 호출할 수 있게 해줌
      • 같은 함수, 변수 등 이어도 namespace가 다르면 전혀 다른 개체로 인식된다
      • 네임스페이스와 다중정의
        • 다중 정의의 조건은 이름이 같아야 한다, 이때 이름이 같다는 것은 namespace도 같다는 뜻을 포함한다
        • 이름이 같고, 모든것이 같아도 namespace가 다르면 다른 개체! // 이때 호출시 네임스페이스를 구별해 주지 않으면 모호성에 의해 컴파일 오류가 발생한다
    • 식별자 검색 순서
      • 식별자가 선언된 위치를 검색하는 순서 // 이때 호출자보다 먼저 선언되야 함(윗줄에 존재해야함)
      • 전역 함수읜 경우
        1. 현재 블록 범위
        2. 현재 블록 범위를 포함하고 있는 상위 블록 범위(Max는 함수 몸체)
        3. 가장 최근에 선언된 전역변수 나 함수
        4. using 선언된 네임스페이스 혹은 전역 네임스페이스 / 이때 두 곳에 동일한 식별자 존재 시 컴파일 요류
      • 클래스 메서드인 경우
        1. 현재 블록 범위
        2. 현재 블록 범위를 포함하고 있는 상위 블록 범위(Max는 함수 몸체)
        3. 클래스의 멤버
        4. 부모 클래스의 멤버
        5. 가장 최근에 선언된 전역 변수나 함수
        6. 호출자 코드가 속한 네임스페이스의 상위 네임스페이스
        7. using 선언된 네임스페이스 혹은 전역 네임스페이스 / 이때 두 곳에 동일한 식별자 존재 시 컴파일 요류

연습문제

1. 다음 두 함수 원형에서 잘못된 점은 무엇인지 답하세요

- int TestFunc(int nParam1 = 5, int nParam2, int nParam3 = 10) 

- int TestFunc(int nParam1 = 5, int nParam2) 

= 초깃값 설정은 오른쪽부터, 중간에 빼먹을 수 없음

2. 다음 두 함수를 호출하는 코드에서 문제가 발생하는 이유

void TestFunc(int a) { std::cout << "TestFunc(int)" << std::endl; }

void TestFunc(int a, int b = 10) { std::cout << "TestFunc(int, int)" << std::endl; }

 = 함수의 모호성이 발생하기 때문( TestFunc(10) 실행시 모호성 오류 발생 )

3. 함수를 다중정의 하는것보다 템플릿이 더 좋은 코드가 될 가능성이 높은 이유?

= 템플릿으로 함수를 작성하면 유지보수 및 관리가 쉬워진다(다중정의는 N개를 바꿔야함, 템플릿은 하나만 바꾸면 됨)

4. inline 함수와 매크로의 공통된 장점

= 대입한다( 메모리 사용량이 낮아진다 )

5. 네임스페이스 미리 선언하는 법

= using namespace

6. 다음 코드의 실행결과

#include <iostream>

using namespace std;

 

int nData = 200;

 

namespace Test {

    int nData = 100;

    void TestFunc(void) {

        cout << nData << endl; // 여기서의 nData가 가리키는 것은? 1은 없음, 2로 100

    }

}

 

int _tmain(int argc, _TCHAR* argv[]) {

    TEST::TestFunc(); // 연산자 찾기

 

    return 0;

}

 

 

= 100

 

'IT공부 > 이것이 C++이다' 카테고리의 다른 글

객체의 관계 규정과 설계_1  (0) 2022.03.16
객체지향 프로그래밍_2  (0) 2022.03.12
객체지향 프로그래밍_1  (0) 2022.03.11
C 에서 C++로 문법 전환하기_1  (0) 2022.03.07

#include <stdio.h>

 

typedef struct { // 사람 구조체, x = 몸무게, y = 키

    int x;

    int y;

    int rank;

}Man;

 

int main(int argc, const char * argv[]) {

    int n;

    scanf("%d", &n);

    

    Man arr[n];

    for(int i=0; i<n; i++) {

        scanf("%d %d", &arr[i].x, &arr[i].y);

    }

    

    for(int i=0; i<n; i++) { // rank 매기기

        int rank = 1;

        for(int j=0; j<n; j++) // rank = 자신보다 rank 가 높은 사람의 수 + 1 

            if(arr[i].x < arr[j].x && arr[i].y < arr[j].y)

                rank++;      

        arr[i].rank = rank;

    }

    

    for(int i=0; i<n; i++) {

        printf("%d ", arr[i].rank);

    }

        

    return 0;

}

'IT공부 > beakjoon 알고리즘' 카테고리의 다른 글

객체지향프로그래밍_3  (0) 2022.03.13
1436번: 영화감독 숌  (0) 2022.03.13
1018번: 체스판 다시 칠하기  (0) 2022.03.11
2231번:분해합 문제  (0) 2022.03.06

Chapter.1 C 와는 다른 C++

  • C와 C++의 차이
    • C언어의 자료형에 대한 핵심
      1. 정수형이나 문자형 같은 자료형: 자료형이 다르면 사용 불가능
      2. 구조체나 공용체: 기존의 자료형을 조합해 새로운 형식의 자료형을 만들어 활용할 수 있다
      3. 포인터: 자료형을 효율적으로 다루기 위해 메모리를 어떻게 이용하는지 이해하기 위한 핵심 개념
    • HellowWord로 본 C++
      • #include "stdafx.h" // standard application frameworks (표준 애플리케이션 프레임 워크) -> visual studio만 사용
      • #include <iostream> // C++ 에서는 표준 헤더파일을 추가할 때 .h 를 붙이지 않는다
      • std::cout << "Hellow World" << std::endl;
        1. std = 네임스페이스(namespace) 개념 상 소속!
        2. :: = 범위 지정 연산자, 스코프 설정 연산자(Scope resolution operator)
        3. cout = 콘솔 출력을 담상하는 객체
        4. << = 연산자 함수
        5. endl = C 언어의 \n 과 같이 개행의 역활 + Fflush와 같이 출력 스트림를 모두 내보내는 역활
          • C언어의 printf 함수보다 효율적 / 출력 전문 객체에게 출력을 맡기는 것 ex) 세탁 직접하기 -> 세탁소에 맡기기
    • 인스턴스와 입출력 흐름
      • 인스턴스(instance) 란? = 객체의 형식을 갖는 변수를 인스턴스 라 한다
      • std::cout
        • iostream 클래스의 인스턴스 이다
        • C와 가장 큰 차이점은 형식문자를 지정하지 않아도 된다는 것이다!
        • << 연산자로 여러 문자열을 추가로 이어 출력할 수 있다
          • ex) std::cout << "저는 " << 20 << "살 " << "입니다."" << std::endl; // 저는 20살 입니다.
      • std::cin
        • iostream 클래스의 인스턴스 이다
        • >> 연산자를 사용, 마찬가지로 형식문자를 지정하지 않아도 된다
          • ex) std::cin >> nAge; // 입력받은 문자, 문자열 등을 nAge 에 저장
    • 자료형
      • 변수의 선언 및 정의
        • int a = 10; = int a(10); // 초깃값이 상수가 아닌 변수 일 경우(int b(a)) 복사 생성자 사용됨
      • auto
        • 초깃값의 형식에 맞춰 선언하는 인스턴스의 형식이 '자동'으로 결정됨
    • 메모리 동적 할당
      • new와 delete 연산자
        • new 연산자 = 객체의 생성자 호출, delet 연산자 = 객체의 소멸자 호출 
        • 일반 변수 
          • 형식 *변수이름 = new 형식;
          • delete 변수이름
        • 배열인 변수
          • 형식 *변수이름 = new 형식[요소개수];
          • delete[] 변수이름;
    • 참조자 형식
      • 형식 &이름 = 원본; // 꼭 선언과 동시에 초기화 해야함 ( 상수에는 참조자 선언 불가 )
      • 포인터와 다르게 한번 짝을 이루게 되면 달라지지 않는다
      • 덩치가 큰 자료는 값이 아니라 '주소'를 전달하는 것이 효율적이기 때문에 존재한다, call-by-reference 가능
      • 호출자 코드로는 매개변수가 참조 형식인지 알 수 없다!
      • r-value 참조
        • int &&radata = 3;
        • r-value 참조자는 곧 사라질 대상에게 참조가 가능하다 ex) 3+2+1 이면 3+2가 먼저 계산된 후 5+1이 계산됨, 이때  5가 곧 사라질 대상
        • 추후 더 설명할 예정
    • 범위기반 for 문
      • for(auto 요소변수 : 배열이름) { 반복문 }
        • 배열의 요소 수에 따라 반복 횟수가 정해지고, 요소 변수는 각 배열의 n번째 요소에 접근하게 해준다
          • ex) int arr[5]; for(auto n : arr) // 5번 반복, 0번째는 n = arr[0], 2번째때 n=arr[2]; 이다
        • 배열의 요소를 변경하려면 &요소변수 형식으로 선언해야 한다
          • ex) for(auto &n : arr)
        • 배열이 바뀌었을 경우 반복문을 수정하지 않아도 되기 때문에 생산성이 향상된다

연습문제

1. 

string name;

int age;

 

cin >> name >> age;

cout << "나의 이름은 " << name << "이고, " << age << "살입니다." << endl;

 

2. auto 는 초깃값의 형식에 따라 자료형을 세팅해준다, ex) auto a(10); // = int a(10);

3. char *arr = new char[12]; / delete[] arr;

4. void swap(int &a, int &b) { int tmp; tmp = a; a = b; b = a; }

5. 기본 참조는 저장되어 있는 변수의 위치를 참조하는 것 이고, 상수형 참조는 곳 사라질 값, 즉 중간 계산 값(임시 결과)를 참조할 수 있다. 

 -- ??

6. for(auto n : aList) { cout << n << " ";} cout << endl;

 

 

'IT공부 > 이것이 C++이다' 카테고리의 다른 글

객체의 관계 규정과 설계_1  (0) 2022.03.16
객체지향 프로그래밍_2  (0) 2022.03.12
객체지향 프로그래밍_1  (0) 2022.03.11
C에서 C++ 문법 전환하기_2  (0) 2022.03.09

문제

어떤 자연수 N이 있을 때, 그 자연수 N의 분해합은 N과 N을 이루는 각 자리수의 합을 의미한다. 어떤 자연수 M의 분해합이 N인 경우, M을 N의 생성자라 한다. 예를 들어, 245의 분해합은 256(=245+2+4+5)이 된다. 따라서 245는 256의 생성자가 된다. 물론, 어떤 자연수의 경우에는 생성자가 없을 수도 있다. 반대로, 생성자가 여러 개인 자연수도 있을 수 있다.

자연수 N이 주어졌을 때, N의 가장 작은 생성자를 구해내는 프로그램을 작성하시오.

 

==================================================

 

#include <stdio.h>

 

int SQUARED(int n) { // 자릿수 를 위해 10^(n-1) 을 반환하는 함수

    int value = 1;

    for(int i=1; i<n; i++)

        value*=10;

    

    return value;

}

 

int main(int argc, const char * argv[]) {

    

    int M; // 입력받은 M

    

    scanf("%d", &M);

    

    for(int i=0; i<M; i++) { // 0부터 생성자인지 비교하며 올라감, 생성자면 바로 return

        int count = 0, num = i, value = i; // count 는 i의 자릿수, num은 i대신 사용할 도구, value 는 생성자인지 확인하는 값

        

        while(1) { // count 에 i 의 자릿수 입력

            num/=10;

            count++;

            if(num==0)

                break;

        }

        

        num = i; // 도구 num 초기화

        for(int j=count; j>0; j--) { // 각 자릿값을 value 에 더하기 (본인의 값은 이미 더해져 있음)

            value += num/SQUARED(j);

            num %= SQUARED(j);

        }

        

        if(value == M) { // 생성자인지 비교

            printf("%d\n", i);

            return 0;

        }

        

    }

       

    printf("0\n"); // 생성자 없을 경우 0 반환

    return 0;

}

'IT공부 > beakjoon 알고리즘' 카테고리의 다른 글

객체지향프로그래밍_3  (0) 2022.03.13
1436번: 영화감독 숌  (0) 2022.03.13
1018번: 체스판 다시 칠하기  (0) 2022.03.11
7568번: 덩치  (0) 2022.03.08

Chapter.6 매크로와 선행처리기

  • 선행처리기와 매크로
    • 선행처리기 : 컴파일 이전의 처리
         
    • 선행처리 명령대로 소스코드의 일부를 단순 치환한다 이때 #을 붙이고, 세미콜론은 붙이지 않는다
  • 대표적인 선행처리 명령문
    • #define PI 3.141592
      • #define(지시자), PI(매크로), 3.141592(매크로 몸체) 라 표현한다
      • 뜻은 매크로PI를 매크로몸체 3.14~로 치환해라 라는 뜻
    • #define SQUARE(X) X*X
      • 함수와 유사한 메크로(functuon-like macro) 즉 매크로 함수 이다
      • SQUARE(X) 등장시 X*X로 치환하라는 뜻이다 ex) SQUARE(123) -> 123*123
    • 잘못된 매크로 정의
      • ex) SQUARE(3+2) 의 경우 3+2*3+2 = 11이 출력된다(25가 아니라)
      • 이때 3+2에 괄호를 쳐주면 (3+2)*(3+2) = 25로 정상적인 값이 나오게 된다
      • 따라서 매크로 몸체에 괄호를 쳐준다 SQUARE(X) ( (X)*(X) ) // 매개변수에 괄호, 전체 함수에 괄호
    • 두줄에 걸쳐 매크로 정의하기
      • define SQUARE(X) \
      • ((X)*(X))
    • 매크로 정의 시, 먼저 정의된 매크로도 사용 가능!
    • 매크로 함수의 장점
      1. 일반 함수에 비해 실행속도가 빠르다
      2. 자료형에 따라 별도로 함수를 정의하지 않아도 된다
    • 매크로 함수의 단점
      1. 정의하기가 정말로 까다롭다
      2. 디버깅 하기가 쉽지 않다
    • 따라서 매크로 할 함수의 특징
      1. 작은 크기의 함수
      2. 호출의 빈도수가 높은 함수
  • 조건부 컴파일을 위한 매크로
    • #if... ~ #endif = 참이라면
      • #if 뒤에 오는 인자가 참이면 #endif 전까지 있는 코드 컴파일, 참이 아니면 #endif 전까지 있는 코드 생략!
    • #ifdef... ~ #endif = 정의 되었다면
      • #ifdef 뒤에 오는 매크로가 정의되어 있으면 #endif 전까지 있는 코드 컴파일, 정의되지 않으면 #endif 전까지 있는 코드 생략!
    • #ifndef... ~ #endif = 정의 되었다면
      • #ifndef 뒤에 오는 매크로가 정의되지 않으면 #endif 전까지 있는 코드 컴파일, 정의되어 있으면 #endif 전까지 있는 코드 생략!
    • #else의 삽입 
      • #if, #ifdef, #ifndef 에 사용 가능하다
      • if문과 동일하게 사용된다
    • #elif의 삽입
      • #if 문에만 사용 가능하고 여러번 사용 가능하다
      • if문의 elseif와 동일하게 사용된다
  • 매개변수의 결합과 문자열화
    • 문자열 내에서는 매크로의 매개변수 치환이 발생하지 않는다
      • ex) define ST_job(A, B) "A의 직업은 B입니다" 선언후 ST_job(이중현, 학생) 실행시  A의 직업은 B입니다 가 치환된다
    • 따라서 문자열 내에서 매크로를 치환하려면 # 연산자를 사용면 된다
      • ex) define ST_job(A, B) #A "의 직업은" #B "입니다" 는 이중현의 직업은 학생입니다 로 치환된다
    • 필요한 형태대로 단순하게 결합하기 : 매크로 ##연산자
      • ex) define STNUM(Y, S, P) Y ## S ## P 선언후 STNUM(18, 11, 21) 은 181121 로 치환된다

Chapter.7 파일의 분할과 헤더파일의 디자인

  • 파일의 분할
    • 컴파일러는 파일 단위로 컴파일을 진행한다, 따라서 다른 파일의 정보를 참조하여 컴파일을 진행하지 않는다
    • 외부에 선언 및 정의되어 있다면 컴파일러에게 미리 알려줘야 한다!!
      • extern int num; -> 외부에 int num 이라는 변수가 선언되어 있다 라고 알려준다
    • 다른 파일에서 접근을 못하게 막고 싶다면 static을 선언하면 된다 (static int num;) -> 접근 범위를 파일 내부로 제한한다
  • 헤더파일의 디자인과 활용
    • #include 지시자의 의미 = 이 문장의 위치에 해당 파일에 저장된 내용을 가져다 놓으세요
    • 헤더파일을 include 하는 두가지 방법
      1. #include <헤더파일 이름> = C의 표준에서 정의하는, 기본적으로 제공되는 헤더파일을 포함시킬때 사용
      2. #include "헤더파일 이름" = 프로그래머가 정의한 헤더파일을 포함시킬때 사용
    • 헤더파일에 담겨야 하는 내용
      • extern 이 선언되어야 하는 함수, 변수를 미리 선언해 놓는다
      • 구조체를 저장해 사용할 경우 헤더파일에 저장해서 모두 사용할 수 있게 한다
      • 헤더파일의 중복 삽입 문제
      • 다음과 같은 경우 구조체 div가 두번 삽입된 형태가 되어 컴파일 에러가 발생한다
        • 헤더파일의 중복 삽입이 문제가 아니라 구조체의 중복 선언이 문제
        • 이때 #ifndef __STDIV_H__ 를 사용해 조건부 컴파일을 사용하면 된다 (크게 의미없는 매크로를 사용한다)
        • ex) stdiv2.h 헤더파일 구현시
          • #ifndef __STDIV2_H__
          • #define__ STDIV2_H__
          • ~~ ~~ ~~
          • #endif
        • 를 사용해서 중복 삽입이 됬을 경우 컴파일이 되지 않게 선언해주면 된다(중복 선언은 되지만, 안에 내용이 없는 상태로 치환되기 때문에 문제가 발생하지 않음)

 

 

 

 

 

 

'IT공부 > 윤성우 열혈 C프로그래밍' 카테고리의 다른 글

C언어의 깊은 이해_3  (0) 2022.02.10
C언어의 깊은 이해_2  (0) 2022.02.09
C언어의 깊은 이해_1  (0) 2022.02.07
포인터와 배열의 시작_4  (0) 2022.02.07
포인터와 배열의 시작_3  (0) 2022.02.05

Chapter.4 파일 입출력

  • 파일과 스트림(Stream), 그리고 기본적인 파일의 입출력
    • 파일에 저장되어 있는 데이터 읽기
      • 파일에 저장되어 있는 데이터를 참조하기 위해서는 파일과 프로그램 사이의 통로를 만들어야 한다
      • 이때 프로그램과 파일을 잇는 통로 역활을 하는것이 Stream 스트림 이다
      • 스트림의 진행방향은 꼭 한 방향이다
             
      • 이 스트림의 형성은 운영체제의 몫이고 우리는 스트림 생성을 요구하면 된다
    • fopen함수 호출을 통한 파일과의 스트림 형성과 FILE 구조체
      • fopen 함수는 스트림을 형성(요구) 할 때 호출하는 함수이다
        • FILE * fopen(const char* filename, const char * mode); // 성공시 FILE 구조체의 변수 주소 값, 실패시 NULL
        • 첫 인자는 스트림을 형성할 파일의 이름, 두번째 인자로는 스트림 종류에 대한 정보
      • fopen 함수 호출 -> FILE 구조체 변수 형성 -> 구조체 변수에 파일에 대한 정보가 담긴다 즉 파일을 가리키는 지시자 역활
    • 입력 스트림과 출력 스트림의 생성
      • 출력 스트림의 형성을 요구하는 fopen / FILE * fp = fopen("data.txt", "wt"); // 파일 data.txt 과 wt모드로 스트림 형성
      • 입력 스트림의 형성을 요구하는 fopen / FILE * fp = fopen("data.txt", "rt"); // 파일 data.txt 과 rt모드로 스트림 형성
        • cf) 파일과 스트림이 형성된 경우를 파일이 열렸다(개방, 오픈) 이라고도 표현한다
    • 파일에 데이터 입력하기
      1. 출력 모드로 파일 열기 / FILE * fp = fopen("data.txt", "wt"); // 이때 파일에 경로 지정 가능!
      2. 파일에 데이터 입력하기 / fput('A', fp); // fput의 두번째 인자인 stream 에 파일 구조체 포인터를 입력해 준다
      3. 스트림의 연결을 종료해 주기 / fclose(fp);
    • 스트림의 소멸을 요청하는 fclose 함수
      • int fclose(FILE * stream); // 성공시 0, 실패시 EOF 반환
      • 파일을 닫아주는 이유
        1. 운영체제가 할당한 자원의 반환
        2. 버퍼링 되었던 데이터의 출력
      • 이때 출력버퍼의 데이터를 비우기 위해선 fflush 함수를 사용해도 된다 
      • 입력 버퍼의 경우 데이터를 비우면 소멸되기 때문애 fflush 함수를 사용할 수 없다!!!
    • 파일로부터 데이터 입력받기
      1. 입력 모드로 파일 열기 / FILE * fp = fopen("data.txt", "rt"); 
      2. 파일에서 데이터 입력받기 / int ch = fgetc(fp);
      3. 스트림의 연결을 종료해 주기 / fclose(fp);
  • 파일의 개방 모드(Mode)
    • 스트림을 구분하는 기준1: 읽기위해? or 쓰기위해?
           
    • 스트림을 구분하는 기준2: 텍스트 모드와 바이너리 모드 
      • 텍스트 파일과 바이너리 파일의 구분
        1. 텍스트 파일 : 문자 데이터 ex) 도서목록, 물품내역
        2. 바이너리 파일 : 컴퓨터가 인식하는 데이터 ex) 영상파일, 음원파일
      • 개행문자 \n 에 관한 부가설명
        • C언어에서는 \n을 개행문자로 인식하지만 모든 컴퓨터 환경이 그렇진 않다
          • ex) Winodw = \r\n, MAC = \r, Unix 계열 = \n
          • 이때 텍스트 모드로 파일을 열면 자동으로 변환해준다
      • 텍스트 모드, 바이너리 모드의 구분
        모드(mode) 스트림의 성격
        b 바이너리 모드
        t 텍스트 모드
        ' '(선언X) 텍스트 모드
  • 파일 입출력 함수의 기본
    • 전에 학습한 파일 입출력 함수를 이용한 파일 입출력
      1. int fputc(int c, FILE * stream) // 문자 출력
      2. int fgetc(FILE * stream) // 문자 입력
      3. int fputs(const char * s, FILE * stream) // 문자열 출력
      4. char * fgets(char * s, int n, FILE * stream) // 문자열 입력
        • cf) 문자열을 파일에 저장할 때는 널문자로 구분 X, 개행문자(\n)으로 문자열을 구분하게 된다
        • 따라서 문자열을 읽어들이는 함수를 호출하면 개행문자(\n)을 만날때 까지 게속 읽어들인다
    • feof함수 기반의 파일복사 프로그램
      • 파일의 마지막을 확인하는 feof함수
        • int feof(FILE * stream); // 파일의 끝에 도달하면 0, 아닐경우 다른 값 반환
    • 바이너리 데이터의 입출력: fread, fwrite
      • size_t fread(void * buffer, size_t size, size_t count, FILE * stream); // 성공시 전달인자 count, 실패시 작은값
        • ex) int buf[12];, fread((void*)buf, sizeof(int), 12, fp); // 성공시 12반환, 실패시 12보다 작은 값 반환
        • sizeof(int)크기의 데이터 12개를 fp로부터 읽어들여 배열 buf에 저장 
      • size_t fwrite(void * buffer, size_t size, size_t count, FILE * stream); // 성공시 전달인자 count, 실패시 작은값
        • ex) int buf[7] = { ~ };, fwrite((void*)buf, sizeof(int), 7, fp); // 성공시 7반환, 실패시 7보다 작은 값 반환
        • sizeof(int)크기의 데이터 7개를 buf로부터 읽어들여 fp에 저장
  • 텍스트 데이터와 바이너리 데이터를 동시에 입출력 하기
    • 서식에 따른 데이터 입출력: fprintf, fscanf
      • printf, scanf 함수와 동일하게 사용한다
      • fprintf(fp, "%s %c %d", name, sex, age); // name문자열, sex문자, age바이너리 데이터를 파일에 출력함
      • fscanf(fp, "%s %c %d", name, &sex, &age); // name문자열, sex문자, age바이너리 데이터를 파일에서 읽어들임
    • 텍스트와 바이너리 데이터의 집합체인 구조체 변수의 입출력
      • 구조체로 묶여있는 여러개의 데이터들을 하나의 바이너리 데이터로 인식시켜 입출력 시킬 수 있다
      • fread, fwrite 함수 사용
  • 임의 점급을 위한 '파일 위치 지시자'의 이동
    • 파일 위치 지시자란?
      • FILE 구조체의 맴버 중 하나로, 파일의 위치 정보를 저장하고 있다
      • fgets, fputs 를 사용하면 다음 문자열을 입출력 할 수 있게 파일 내의 위치를 참조하고 있다
    • 파일 위치 지시자의 이동: fseek
      • 파일 지시자를 이동시킬 때는 fseek 함수를 호출한다
      • int fseek(FILE * stream, long offset, int wherefrom); // 성공시 0, 실패시 0이 아닌 값 반환
        • stream으로 전달된 파일 위치 지시자를 wherefrom 으로부터 offset 바이트 만큼 이동시켜라!
               
      • 현재 파일 위치 지시자의 위치는?: ftell
        • 현재의 파일 위치 지시자의 정보를 확인하고 싶다면 ftell 함수를 호출하면 된다
        • long ftell(FILE * stream) // 파일 위치 지시자의 위치 정보 반환
          • 첫번째 바이트를 가리킬 경우 0을 반환하고, 세번째 바이트를 가리킬 경우 2를 반환한다.

Chapter.5 메모리 관리와 메모리의 동적할당

  • C언어의 메모리 구조
    • 메모리의 구성
         
    1. 코드영역(Code Area) : 실행할 프로그램의 코드가 저장되는 메모리 공간
    2. 데이터 영역(Data Area) : 전역변후와 static으로 선언되는 static 변수가 할당되는 공간(프로그램 종료시 까지 유지)
    3. 힙 영역(Heap Area) : 프로그래머가 원하는 시점에 할당하여 사용하고, 반환할 수 있는 영역
    4. 스택 영역(Stack Area) : 지역변수와 매개변수가 할당되는 영역, 함수를 빠져나가면 소멸하게 된다!
  • 메모리의 동적 할당
    • 전역변수와 지역변수로 해결이 되지 않는 상황
      • 문자열 배열을 함수로 반환하는 상황 -> (함수내에서 선언된 배열은 지역변수 이므로 함수가 끝나서 반환한 후에 사라진다 이때 반환된 값은 주소 값이기 때문에 주소 값이 가리키는 곳에는 아무것도 없는 상태가 된다)
      • 배열을 전역변수로 선언했을 경우 -> 하나의 배열로 여러 값을 입력받을 수 없게 된다, 여려개의 전역변수를 할당하면 데이터 영역에서 프로그램에 부하를 주게 된다
      • Solution = 생성과 소멸의 시기가 지역변수나 전역변수와 다른 유형의 변수를 선언해 준다!
    • 힙 영역의 메모리 공간 할당과 해제: malloc 과 free 함수
      • void *  malloc(size_t size); // 힙 영역으로의 메모리 공간 할당 / -> 메모리 공간의 첫번째 바이트 주소 값 반환
      • void free(void * ptr) // 힙 영역에 할당된 메모리 공간 해제
        • malloc 함수는 성공시 할당된 메모리의 주소 값, 실패시 NULL 반환
      • 이 주소 값을 이용하여 데이터에 접근하면 된다 즉 포인터 연산으로 값에 접근(연산) 한다!
    • molloc 함수의 반환형이 void*(보이드 형 포인터)인 이유와 힙 영역의 접근
      • molloc함수의 인자로는 숫자(Byte) 만 주기 때문에 포인터 형에 대한 결정을 스스로 할 수 없다
      • 따라서 형변환을 사용하여 직접 포인터 형을 맞추어서 선언해 주어야 한다
        • ex) int * ptr = (int*)malloc(sizeof(int)*7) // int형 포인터로 28byte 동적할당
    • free 함수를 사용하지 않을 시 발행하는 문제점
      • 결국 프로그램을 종료하면 힙 영역에 있던 변수들은 전부 헤제가 된다
      • 그러나 프로그램의 효율적인 메모리 활용을 위해 사용해 주어야 하는것이 좋다;;
    • malloc 함수와 비슷한 colloc 함수
      • void * calloc(size_t elt_count, size_t elt_size); // 성공시 할당된 메모리 주소 값, 실패시 NULL
        • malloc과 기능은 동일하지만 인자의 개수가 다르다, 초기화 차이가 있다
        • calloc 은 elt_size(몇 바이트 크기의 블록) elt_count(개수) 를 힙 영역에 할당해 달라는 뜻
          • ex) colloc(30, sizeof(int)); = malloc(120);
          • malloc은 메모리 공간을 초기화 하지 않지만 colloc은 메모리 공간의 비트를 0으로 초기화 한다
    • 힙에 할당된 메모리 공간 확장 시 호출하는 realloc 함수
      • 원래라면 한번 할당된 공간은 확장할 수 없다
      • 그러나 힙 영역에 할당된 공간은 늘릴 수 있다
      • void * realloc(void * ptr, size_t size); // 성공 시 새로 할당된 메모리의 주소 값, 실패시 NULL
        • int * arr = (int*)malloc(sizeof(int)*3);
        • arr = (int*)realloc(arr, sizeof(int)*7);
        • 이때 메모리 공간 상태에 따라 실행 결과는 2가지로 나뉜다
          1. 기존 메모리를 할당한 영역 뒤에 확장할 영역이 넉넉한 경우
            • 전 molloc 함수의 반환 주소 값과 realloc 함수의 반환 주소 값이 동일하다
          2. 기존 메모리 영역 뒤 확장할 영역이 없는 경우
            • 전 molloc 함수의 반환 주소값과 다른 새로운 주소 값이 반환된다(새로운 곳에 공간을 새로 할당한다)

'IT공부 > 윤성우 열혈 C프로그래밍' 카테고리의 다른 글

C언어의 깊은 이해_4  (0) 2022.03.06
C언어의 깊은 이해_2  (0) 2022.02.09
C언어의 깊은 이해_1  (0) 2022.02.07
포인터와 배열의 시작_4  (0) 2022.02.07
포인터와 배열의 시작_3  (0) 2022.02.05

+ Recent posts