C++

독하게 시작하는 C 프로그래밍 1 – 널널한 개발자 TV

 

 

https://www.youtube.com/watch?v=I5jmg6uUTbQ&list=PLXvgR_grOs1AQuQ-5mWbx0zdG0betdeoL&index=1

 

 

  1. 제1장 C 프로그래밍 입문 – 첫 번째
  2. 제1장 두 번째
  3. 제2장 자료형 – 첫 번째
  4. 제2장 두 번째
  5. 제3장 표준 입/출력 도구 – 첫 번째
  6. 제3장 두 번째
  7. 제4장 연산자 기본 – 첫 번째
  8. 독하게 시작하는 C 제4장 두 번째
  9. 독하게 시작하는 C 제5장 연산자 응용 – 첫 번째
  10. 독하게 시작하는 C 제5장 두 번째
  11. 독하게 시작하는 C 제6장 기본 제어문 – 첫 번째
  12. 독하게 시작하는 C 제6장 두 번째
  13. 독하게 시작하는 C 제7장 반복문
  14. 독하게 시작하는 C 제8장 배열
  15. 독하게 시작하는 C 제9장 – 배열을 활용한 프로그래밍 기법
  16. 독하게 시작하는 C 제10장 함수에 대한 기본 이론

 

 


 

2. 제1장 두 번째

 

HelloWorld.c
소스코드 (인간이 인식하는 언어)
High Level 언어

# 컴파일러 : 소스코드를 기계어로 번역
컴파일은 사람이 작성한 소스 코드를 CPU 가 인식할 수 있는 명령어로 번역하는 과정

1단계HelloWorld.c : 설계도
2단계 : HelloWorld.obj : 부품 (컴파일(Compile))
3단계 : HelloWorld.exe : 완성품 (링크(Link)) 실행가능한 기계어 코드

.h 선언
.c 정의

 

#include <stdio.h>

int main(void)
{
    printf("Hello, World\n");
    return 0;
}

 

# 함수 선언 정의
int main(void) : 프로그램 시작
반환형식 함수이름(매개변수)

#include : 전처리기 (프리프로세서) 컴파일 전에

# 컴파일을 했는데 오류가 나면 F4 키를 누루면 해당 오류 라인을 알려줌.

# void : 없음 (명확히 해주기 위해서 적음.)

 


 

3. 제2장 자료형 – 첫 번째

 

# 자료형 : 일정 길이의 메모리에 저장된 정보를 해석하는 방법

32bit : 42.95억
메모리 최대 범위 : 4기가
OS 32 bit : 램 4기가 밖에 못씀.

64비트
2의 64승 16EB

TB -> PB -> EB -> ZB -> YB

자료형은 숫자이다.

8비트 : char, unsigned char
16비트 : short, unsigned short
32비트 : int, unsigned int, long, unsigned long

# 변수는 사용에 앞서 반드시 선언해야 한다.
int a; 선언
a = 10; 정의
int a = 19; 선언 및 정의

변수: 이름, 주소, 값

 


 

4. 제2장 두 번째

 

C99

char : 8비트
short : 16비트
int : 32비트
long : 32비트 또는 64비트
long long int 64비트 %lld (long 형식이 모호해서 탄생됨)

# 부동 소수점 형식
float : 단정도 32비트 (유효 자릿수 소수점 이하 6자리) f 나 F를 붙인다. (없으면 double)
double : 배정도 64비트 (유효 자릿수 소수점 이하 15자리)
long double : 특수정도 (지원 안하는 컴파일러는 long 과 같이 취급) 80비트
(VC++ 은 지원 안함, 리눅스 계열에서 지원)

# 실수 형식 : 오차를 가짐 (근사값 처리 때문에)

# float 형식은 절때 쓰지 마라. 정확도가 떨어진다. 반드시 double을 써라.

# 배열의 이름은 주소

# 문자열 끝에는 항상 널문자가 온다. \0

# char szBuffer[12] (string zero : 널로 끝나는 문자열)

 

#include <stdio.h>

int main(void)
{
    char ch1 = 'A', ch2 = 'B', ch3 = 'C';
    char szData[4] = { 'A', 'B', 'C' };
    char szNewData[4] = { "ABC" };
    char szNewNewData[12] = { 'A', 'B', 'C' }; // ABC 나머지 공간은 0으로 채움
    char szNewNewNewData[12] = { "ABC" }; // ABC 나머지 공간은 0으로 채움
    return 0;
}

 

 


 

5. 제3장 표준 입/출력 도구 – 첫 번째

 

USER
Kernel
H/W

# User 는 요구를 하고 I/O 는 커널이 한다.

# buffered I/O
getchar() : 버퍼에서 1글자를 꺼내옴.
scanf() : 버퍼에서 형식 문자에 맞게 꺼내옴. (scanf_s()를 써라.)
gets() : 버퍼에서 한 줄씩 꺼내옴. (심각한 보안결함이 있다. gets_s()를 써라.)

# Buffer : Memory
완충기
유튜브에서 네트워크가 끊김이 있더라도
버퍼를 사용하기 때문에 사용자는 매끄럽게 영상을 감상할 수 있다.

# Non Buffered I/O : 버퍼를 사용하지 않고 직접 입력 받음
_getch() : #include <conio.h>

fflush() : 버퍼를 비우는 함수

 


 

6. 제3장 두 번째

 

getchar()
표준입력장치(stdin)로부터 문자 하나 반환
버퍼가 비어있다면 사용자로부터 입력을 받아 버퍼를 채운 다음 첫 번째 문자를 반환
버퍼가 채워져 있다면 버퍼에서 한 글자 반환

putchar(int c)
표준출력장치(stdout)인 콘솔에 한 글자 출력

putchar(“\n”);
‘\n’ : char (정수값)
“\n” : char[] (주소)

ASLR (Address Space Layout Random) : 메모리 해킹 방지
프로그램을 실행할 때마다 메모리의 위치가 랜덤으로 계속 바뀜

printf()
%c : int (char)
%d : int (부호 있는 10진수)
%o : int (Octal 8진수)
%u : unsigned int (부호 없는 10진수)
%x, %X : 16진수
%e, %E : (float, double) 지수형 소수
%f : double(float) (10진형 소수)
%g : double (%e 나 %f 의 짧은 형태로 출력)
%p : pointer (16진수 주소로 출력)
%s : string (문자열)

 

# printf(“%d\n”, ‘A’ + 1); // char 형과 int 형을 더하면 int 형으로 변환 (타입 프로모션)

 

#include <stdio.h>

int main(void)
{
    char szName[12] = { "Hello" };
    gets_s(szName, sizeof(szName)); // 마지막 fe 는 gets_s 함수가 갖다 붙인거임.
    // Linux, UNIX : fgets(szName, sizeof(szName), stdin);

    char szName[32] = { 0 };
    printf("이름을 입력하세요 :");
    gets_s(szName, sizeof(szName));

    printf("당신의 이름은 ");
    puts(szName);
    puts("입니다.");

    printf("%d\n", 'A' + 1);  // char 형과 int 형을 더하면 int 형으로 변환 (타입 프로모션)
    
    FILE* fp = stdin;  // 브레이크포인트를 걸어서 stdin 버퍼를 확인해보자.
    getchar();
    getchar();
    getchar();
    getchar();

    int nData = 0;
    scanf_s("%d", &nData);

    return 0;
}

 

 

#include <stdio.h>

int main(void)
{	
    FILE* fp = stdin;
    int nAge = 0;
    printf("나이를 입력하세요: ");
    scanf_s("%d", &nAge);  // 엔터키나 스페이스 키는 버퍼에 남아있는다.
    

    getchar();  // 엔터키를 없애기 위해서. 스페이스키는 안됨.
    fflush(stdin);  // 엔터키를 없애기 위해서 버퍼를 비워준다.. 안해주면 아래 gets_s() 에서 작동 안함. (윈도우에서만. 해봤는데 안됨)

    char szName[12] = { 0 };
    printf("이름을 입력하세요: ");
    gets_s(szName, sizeof(szName));

    printf("%d, %s\n", nAge, szName);
    return 0;
}

 

 

int nAge = 0;
printf("나이를 입력하세요: ");
scanf_s("%d%*c", &nAge);  // %*c : 버퍼에서 한 글자 날리기

 

 


 

7. 제4장 연산자 기본 – 첫 번째

 

L-value R-value

int a;
a = 10;
변수(메모리) = 상수

l-value : Left 또는 Location (위치 지정자)
r-value : Right

lvalue 는 모두 rvalue 가 될 수 있다.
rvalue 는 lvalue 가 될 수 없다.

const int a = 10; 상수가 됨
a = 5; // Copy & Overwrite

 

# 표현 범위가 큰 형식이 이긴다.

‘A’ + 1;
char(1바이트) + int(4바이트) => int
65 + 1 = 66

type promotion (승격)
123.45 + 1 => double
double(실수, 8바이트) + int(4바이트)

5 / 2 = 2.5 (double 실수)
5 / 2 = 2  // 2.5 아님
int / int = int  // 소수점 이하 절사

5 / 2.0 = 2.5 (printf 에서 %f 또는 %lf 로 출력)
int / double = double (type promotion)

# 나머지 연산자와 나누기 연산자는 둘 다 나누기를 한다.
7 / 2 = 3 (int)
7 % 2 = 1 (int)

# 몫과 나머지를 구한다면 / 연산자와 % 연산자 두 번 해야 함.

 

 


 

독하게 시작하는 C 제4장 두 번째

 

# 변수는 반드시 초기화 후 사용해야 한다.

프로젝트 / 속성 (Alt + F7)
# 초기화 하지 않으면 에러 메시지 출력하기
Configuration properties / C/C++ / 코드생성 / 기본 런타임 검사 / 모두(/RTC1, /RTCsu와 동일)

# 초기화 하지 않아도 변수 사용가능하려면
Configuration properties / C/C++ / 코드생성 / 기본 런타임 검사 / 기본값

AND &
OR |
XOR ^
NOT ~
Shift left <<
Shift right >>

 

 

#include <stdio.h>

int main(void)
{	
    printf("%d\n", 3);
    pritnf("%d\n", ~3 + 1); // 3에 1의 보수를 한 후 2를 더하면 음수가 됨. (2의 보수)

    return 0;
}

 

 


 

독하게 시작하는 C 제5장 연산자 응용 – 첫 번째

 

# Pointer
* 간접지정 연산자
& 주소 연산자

# sizeof 컴파일 타임 연산자
// 가급적 자주 사용하라.
// 성능에 영향을 안 줌.

int a = sizeof(1); // int형 4바이트
int b = sizeof('1'); // int형 4바이트 (작은 따옴표는 int 형이다.)
int c = sizeof(char); // char형 1바이트

int nData;
int d = sizeof(nData); // int형 4바이트
int e = sizeof(nData + 1.2); // double형(형 승격)
printf("%d %d %d %d %d", a, b, c, d, e);  // 4 4 1 4 8

 

# wchar_t 는 환경에 따라 2바이트나 4바이트가 될 수 있다.
ucs16 : 2바이트
usc32 : 4바이트

sizeof(wchar_t); // 2

 

int aList[5];
memset(aList, 0, sizeof(aList));  // 유지보수를 위해서
memset(aList, 0, 20); // 왕초보
    

int aList[5] = { 0 };
printf("%d\n", sizeof(aList)); // 컴파일 되면 아래와 같은 기계어로 된다.
printf("%d\n", 20);  // 컴파일 되면 위와 같은 기계어로 된다.

 

# alt + 8 : 디스어셈블 단축키 (머신코드)

// 아래 두 문장은 컴파일하면 똑같은 기계어 코드가 된다.
printf(“%d\n”, sizeof(aList));
printf(“%d\n”, 20);

 

# 관계 연산의 결과는 1 또는 0이다.

300 < 300.1F
정수 < 실수 (부동소수점 -> 오차 발생 -> 근사값 처리)

# 실수는 절대로 상등 또는 부등 연산하지 말라.

 

#include <stdio.h>

int main(void)
{
    printf("%d\n", 2147483647);  // 2147483647
    printf("%d\n", 2147483648);  // -2147483648

    printf("%f\n", 2147483647.0);  // 2147483647.000000
    printf("%f\n", 2147483648.0);  // 2147483648.000000

    // 부동 소수점 오차로 값이 같다.
    printf("%f\n", 2147483647.0F);  // 2147483648.000000
    printf("%f\n", 2147483648.0F);  // 2147483648.000000

    printf("%f\n", 2147483600.0F);  // 2147483648.000000
    printf("%f\n", 2147483648.0F);  // 2147483648.000000

    printf("%d\n", 2147483600.0F == 2147483648.0F);  // 1

    return 0;
}

 

# switch case 문에서
case 정수: // 실수는 부동소수점 오차 발생으로 switch 문에 사용하지 마라.

 

int aList[5]; // 배열임. 포인터가 아님. 주소이므로 포인터에 저장은 가능
int *aList; // 포인터임

 

# 이형 자료 간의 비교는 표현 범위가 큰 쪽으로 변환됨
printf(“%f\n”, 3 – 2.5); // 0.5 (결과는 double) (3이 double화 됨)

 

 


 

독하게 시작하는 C 제5장 두 번째

 

# 논리 연산자
&& and
|| or
! not

# 쇼트 서킷(Short Circit)
왼쪽에서 오른쪽으로
연산이 빨리 끝나는 식을 왼쪽으로 배치하라.
불필요한 계산은 하지 않도록 배치를 잘해라.

# 쇼트 서킷 예
마음 >= 김혜수 && 외모 >= 설현
마음은 3시간, 외모는 3초라고 한다면
1. A && B // A에서 3시간 걸려도 B에서 거짓이다면 비효율.
2. B && A // B에서 거짓이라면 3초면 끝난다.

1. 빠른 연산
2. 자주 적중할 조건

삼항 연산자
코드 단순화.
조건 ? 항 : 항

#include <stdio.h>

int main(void)
{
    int nData = 0, nInput;
    scanf_s("%d", &nInput);

    if (nInput > 5)
        nData = 10;
    else
        nData = 0;

    nInput > 5 ? (nData = 10) : (nData = 0);

    return 0;
}

 

 


 

독하게 시작하는 C 제6장 기본 제어문 – 첫 번째

 

 

 


 

독하게 시작하는 C 제6장 두 번째

 

# 리팩토링
내부 코드를 정리하는 것.
기능적으로는 달라지지는 않지만 최적화되어서 성능이 올라간다다.

# goto 문은 예외처리 코드에서 가끔 쓰이는 경우도 있다.
하지만 보통 goto문은 쓰지 않는다.

 


 

독하게 시작하는 C 제7장 반복문

 

#include <stdio.h>

int main(void)
{
    char ch;
    while ((ch = getchar()) != '\n')
    {
        putchar(ch);
    }

    return 0;
}

 

 

#include <stdio.h>

int main(void)
{
    int nInput;
    scanf_s("%d", &nInput);

    int i = 0;
    while (i < nInput)
    {
        putchar('*');
        ++i;
    }

    putchar('\n');
    return 0;
}

 

# continue 가급적 쓰지마라. 흐름의 복잡도가 증가한다.

 


 

독하게 시작하는 C 제8장 배열

 

#include <stdio.h>

int main(void)
{
    int aList[3] = { 0 };

    aList[0] = 10;
    aList[1] = 20;
    aList[2] = 30;

    return 0;
}

 

aList : 전체주소
&aList : 전체주소
aList + 0 : 상대주소 하나
&aList[0] : 상대주소 하나
&aList + 1 : 전체주소 + 1, aList[4] 전체주소

 

# 배열의 이름은 주소이다.

 

int aList[3];

aList : 메모리의 주소, 기준주소, int[3], int 3개, 첫번째의 주소
기준주소 + index(정수) => 상대 주소 하나
&aList + 1 : 전체 주소 단위, aList[4] 번째 주소, int[3] 크기, 쓰레기값.

 

 

#include <stdio.h>

int main(void)
{
    int aList[3] = { 0 };

    int* pData = aList;  // 결과는 같다.
    int* pData2 = &aList;  // 결과는 같다.

    return 0;
}

 

 

#include <stdio.h>

int main(void)
{
    int aList[5] = { 30, 40, 10, 50, 20 };
    char szBuffer[6] = { 'H', 'e', 'l', 'l', 'o', '\0' };

    char szData[8] = { "Hello" };

    char* pszBuffer = "Hello";

    puts(szBuffer);
    puts(szData);
    puts(pszBuffer);

    return 0;
}

 

 

#include <stdio.h>

int main(void)
{
    char aData[3][4] ;

    aData[0][3] = 10;
    aData[0][4] = 11; // 실행은 되지만 오류


    return 0;
}

 

 

“Hello” : 상수화된 문자배열
char[6]

배열 전체는 0번 요소의 주소로 식별

문자열 상수는 이름이 없으므로 주소로 식별한다.

주소는 포인터에 담는다.

문자열 -> 가변 길이
배열 -> 고정 길이

char aData[3][4];

aData[0][4]; // aData[1][0] 의 값. 오류

# 2차원 배열은 논리적으로 2차원 배열인 것이지 메모리 구조는 1차원이기 때문이다.

 

#include <stdio.h>

int main(void)
{
    int aList[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    int nTotal = 0;
    int i;
    int* pList = (int*)aList;

    for (int i = 0; i < 12; i++)
        nTotal += pList[i];

    printf("%d\n", nTotal);
    return 0;
}

 

 

#include <stdio.h>

int main(void)
{
    int aList[3][4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
    int nTotal = 0;
    int i;
    //int* pList = (int*)aList;

    for (int i = 0; i < 12; i++)
        nTotal += ((int*)aList)[i];
        // nTotal += aList[0][i];  // 위와 같음

    printf("%d\n", nTotal);
    return 0;
}

 

int aList[3][4];
int aList[12];
위 두 개의 메모리 구조는 같다.
단 접근 방법만 다르다.

char aData[3][4];
char[4] 가 3개 있다는 뜻
aData + 1 하면 aData[1][0] 이 됨.

 

# 리팩토링
내부 코드를 정리하는 것.
기능적으로는 달라지지는 않지만 최적화되어서 성능이 올라간다다.

# goto 문은 예외처리 코드에서 가끔 쓰이는 경우도 있다.
하지만 보통 goto문은 쓰지 않는다.

 


 

독하게 시작하는 C 제9장 – 배열을 활용한 프로그래밍 기법

 

1. 버블정렬 : 매번 교환
2. 선택정렬 : 교환할 항 검색, 1회 교환, 인덱스 이용
3. 퀵소트

 

// 버블 정렬
#include <stdio.h>

int main(void)
{
    int aList[5] = { 30, 40, 10, 50, 20 };	
    int i = 0, j = 0, nTmp = 0;

    for (i = 0; i < 4; ++i)
    {
        for (j = i + 1; j < 5; ++j)
        {
            if (aList[i] > aList[j])
            {
                nTmp = aList[i];
                aList[i] = aList[j];
                aList[j] = nTmp;
            }
        }
    }

    for (i = 0; i < 5; ++i)	
        printf("%d\t", aList[i]);	
    return 0;
}

 

 

// 선택 정렬
#include <stdio.h>

int main(void)
{
    int aList[5] = { 30, 40, 10, 50, 20 };	
    int i = 0, j = 0, nTmp = 0;
    int nIndexMin = 0;

    for (i = 0; i < 4; ++i)
    {
        nIndexMin = i;
        for (j = i + 1; j < 5; ++j)
        {
            if (aList[nIndexMin] > aList[j])
            {
                nIndexMin = j;
            }
        }

        if (i != nIndexMin)
        {
            nTmp = aList[i];
            aList[i] = aList[nIndexMin];
            aList[nIndexMin] = nTmp;
        }
    }

    for (i = 0; i < 5; ++i)	
        printf("%d\t", aList[i]);	
    return 0;
}

 

 


 

독하게 시작하는 C 제10장 함수에 대한 기본 이론

 

int Add(int a, int b)   // 함수 시그니처, 함수 원형
{                           // 함수 바디 시작
int x;                     // 지역변수 + 자동변수
}                          // 끝

컴파일러가 기계어로 바꿀 때는 위에서 아래로 간다.
그러므로 특정 함수가 아래에 위치해 있다면 위에 함수 원형을 밝혀준다.

 

#include <stdio.h>

int g_nData = 0;  // 전역 변수

int Add(int, int);  // 원형 선언 -> 헤더 파일 (.h 파일)

int main(void)
{
    int nResult = 0;
    nResult = Add(3, 4);  // 실인수, 임시결과
    printf("%d\n", nResult);
    return 0;
}


int Add(int a, int b)  // 매개변수, 형식인수  // 정의 -> (.c 파일)
{
    int g_nData; // 전역변수보다 지역변수가 우선한다.
    int nResult;  // 지역변수
    nResult = a + b;
    return nResult;
} // 스코프

 

 

Related posts

Leave a Comment