기본적인 C++프로그램

기본적인 C++프로그램은 아래와 같습니다.

1
+2
3
4
5
6
7
8
9
10
/* C++ Hello World!*/
 
#include <iostream>
 
 
int main() {
    std::cout << "Hello\n"//Hello출력후 다음줄
    std::cout << "C++ 첫 프로그램!\n";
    return 0//main문에서 return 뜨면 (종료)
}++++++
cs

line 1, 7, 9 - 주석문


주석문(comment)은 프로그램의 실행에 영향을 미치지 않습니다.

개발자가 프로그램에 대한 설명또는 메모라고 이해하면됩니다.

c++에서는 c와같이 2가지 방법으로 주석문을 생성할수있습니다.

1. 여러줄의 주석이 필요할때 

1
2
/* 내용1
   내용2  */
cs

예제와같이 '/*' 와 '*/' 를 사용하여 주석을 열고 닫습니다.

위 기호 사이는 모두 주석처리하여 컴파일하지 않습니다.


2. 한줄짜리 주석이 필요할때

1
2
3
// 내용 
 
std::cout << "Hello" // Hello
cs

예제와 같이 '//'를 사용하여 한줄짜리 주석을 생성합니다.

'//'뒤에 붙어있는 내용들은 모두 주석처리합니다.




line 6~10 main()함수 및 return문


c언어와 마찬가지로 c++도 첫 컴파일시 main()함수를 먼저 찾고 제일 먼저 실행시킵니다.

main()함수를 발견하지 못할경우 컴파일 오류가 생깁니다.

반드시 하나의 main()함수만 존재하여야합니다.


main()함수의 리턴 타입은 int형이 표준입니다. [int main()]


int main()함수는 return값(함수 종료)을 가지고 있어야합니다. 그러나 c++표준은 main()함수에 한하여 return문을 작성하지 않아도 좋습니다.



line 3 #include <iostream>


전처리기에 대한 지시문입니다. 컴파일 하기전에 <iostream>헤더파일을 읽어 c++ 소스 파일 안에 삽입할 것을 지시합니다.

iostream헤더파일은 c++표준 입출력 클래스와 객체가 선언되어있으므로 꼭 필요한 헤더파일입니다.

1
std::cout << "Hello\n"//Hello출력후 다음줄
cs



line 7, 8 std::cout << "내용";


cout은 c++표준 출력 스트림 객체로 출력한 데이터를 스크린에 출력해주는 역할을 합니다. c언어의 printf역할을 수행한다고 보시면됩니다.

<<연산자는 스트림 삽입 연산자로 왼쪽 스트림 객체에 삽입합니다.

<<연산자는 다양한 기본타입 데이터를 출력할 수 있습니다.

1
2
3
int n = 3;
char c = '#';
std::cout << c << 5.5 << '-' << n << "hello" << true;
cs

실행결과 : #5.5-3hello1

true는 정수1로 출력됩니다.


std::는 cout의 이름공간이 std임을 표시합니다. 코드마다 std::를 넣을수는 없으므로 using 지시어를 사용하여 std::를 생략할수있습니다.

1
2
3
4
5
6
7
8
9
10
/* C++ Hello World!*/
 
#include <iostream>
using namespace std;
 
int main() {
    cout << "Hello\n"//Hello출력후 다음줄
    cout << "C++ 첫 프로그램!\n";
    return 0//0을 반환(종료)
}
cs

line4와같이 using namespace std;를 작성하여주면 std::를 사용하지 않아도 됩니다.

namespace의 자세한 내용은 추후 작성 예정입니다.

C++언어의 역사, 특징, 객체 지향 특성.

기존에 사용되던 C언어는 1972년부터 사용되어왔습니다. 하지만 시대를 거듭할수록 단순 계산뿐만이 아닌 프로그램을 구동시키기 위한 언어가 필요하였고, C언어의 한계를 극복하기 위하여 1979년부터 객체 지향 특성및 기능을 추가한 새로운 언어를 개발하였고 1983년에 C++로 정의되었습니다.



-C++언어는 C 언어의 모든 기능을 가지고 있기 때문에 이미 작성된 C소스 프로그램은 C++프로그램으로 재사용이 가능하고 C목적 코드도 C++ 프로그램에서 링크하여 사용이 가능합니다.


-



C++ 언어의 특징

-C언어로 작성된 프로그램과의 호환성을 유지.

-소프트웨어의 재사용을 통해 소프트웨어 생산성을 높이고, 복잡하고 큰 규모의 소프트웨어 작성, 관리, 유지보수를 쉽가하기위해 데이터 캡슐화, 상속, 다형성등의 객체 지향 개념을 도입한다.

-타입 체크를 엄격히 하여 실행 시간 오류의 가능성을 줄이고 디버깅을 돕는다.

- 실행 시간의 효율성 저하를 최소화한다.



C++에 추가된 기능

함수 중복 : 매개 변수의 개수나 타입이 서로 다른 동일한 이름의 함수들을 선언할 수 있게 한다.

디폴트 매개 변수 : 매개 변수에 값이 전달되지 않는 경우 디폴트 값이 전달되도록 함수를 선얼할 수 있게 한다.

참조 : 변수에 별명을 붙여 변수 공간을 같이 사용할수 있는 참조의 개념을 도입.

참조에 의한 호출 : 함수 호출시 참조를 전달할 수 있게 한다.

new와 delete 연산자 : 동적 메모리 할당, 해제를 위한 new, delete 연산자를 도입한다.

연산자 재정의 : 기존의 연산자에 새로운 연산을 정의할 수 있게 한다.

제네릭 함수와 클래스 : 함수나 클래스를 데이터 타입에 의존하지 않고 일반화 시킬 수 있게 한다.



C++의 객체 지향 특성

그전에 캡슐화는 데이터를 캡슐로 싸서 외부의 접근으로부터 데이터를 보호하는 객체 지향 특성입니다.

C++에서의 캡슐은 클래스라고 정의합니다. class키워드를 사용하며, 객체를 정의합니다.

객체는 클래스라는 틀에서 생겨난 실체이며

C++클래스는 멤버변수, 멤버함수로 이루어지며 각 멤버들은 공개(public),비공개(private)로 선언가능합니다.

1
2
3
4
5
6
7
8
class Circle
{
private:
    int radius; //반지름 값 비공개
public:
    Circle(int r) { radius = r; }
    double getArea() { return 3.14 * radius * radius }
};
cs



상속성

자식이 부모의 유전자를 물려받는것과 비슷합니다. C++에서는 클래스사이에 상속 관계를 두어, 부모 클래스에 선언된 멤버들도 함께 가지고 탄생하게됩니다.


1
2
3
4
class Phone {
    void call(); // 전화 걸기
    void receive(); //전화 받기
};
cs


1
2
3
4
class MobilePhone : public Phone { //Phone을 상속받는다.
    void connectWireless(); // 무선 기지국 연결
    void recharge(); // 배터리 충전
};
cs

1
2
3
4
class MusicPhone : public MobilePhone { //MobilePhone을 상속받는다.
    void dounloadMusic(); // 음악 다운
    void play(); // 음악 재생
};
cs

다형성

하나의 기능이 경우에 따라 다르게 작동하는것입니다.

+연산자를 예로 들면, +연산자 하나로 문자열 연결, 객체 더하기등 피연산자에 따라 서로 다른 연산이 가능합니다.

1
2
3
2 + 3 ==> 5
"남자"+"여자" ==>"남자여자"
 
cs

이러한 현상은 연산자 중복이라고합니다.


또한, 같은 이름의 함수가 매개 변수의 개수나 타입이 다르면 다른함수로 인식되는 함수 중복도 다형성의 하나이다..

1
2
3
void add(int a, int b) {...}
void add(int a, int b, int c) { ... }
void add(int a, double d) { ... }
cs

위 3개의 함수들은 모두 다른함수로 다루어진다.



C++에서 객체 지향을 도입한 목적

- 소프트 웨어 생산성 향상

- 쉬운 모델링



설차 지향와 객체 지향

절차 지향



객체 지향 관계도객체 지향




함수 호출시 인수 전달 방식


-값에 의한 호출 : 본사본이 전달

-참조에 의한 호출 : 원본이 전달




값에 의한 호출

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
void swap(int x, int y);
 
int main()
{
    int a = 100, b = 200;
 
    printf("a=%d b=%d\n", a, b);
    swap(a, b);
    printf("a=%d b=%d\n", a, b);
    return 0;
}
 
void swap(int x, int y)  // a,b 의 값을 복사하기 때문에 swap 함수 내부에서만 바뀐다.
{
    int tmp;
    
    printf("x=%d y=%d\n", x, y);
 
    tmp = x;
    x = y;
    y = tmp;
 
    printf("x=%d y=%d\n", x, y);
 
}
cs

이 방법은 잘못된 방법입니다. 값에 의한 호출을하게되면 복사본이 전달되기때문에 swap함수 내부에서만 바뀌게됩니다. 그렇기때문에 main()함수의 값은 바뀌지 않게됩니다.

swap함수의 x,y와 main함수의 a,b는 완전이 다른 함수라는 것 입니다. 이는 함수의 매개 변수는 기본적으로 값에 의한 호출이기때문에 복사본이 전달됩니다. 같은 이름으로 해도 복사본이 전달되게 됩니다.  이를 해결하기 위한것이 참조에 의한 호출 입니다.



참조에 의한 호출


변수의 복사본이 아닌 원본이 직접 전달 되는 것이다. C언어에서는 포인터를 통하여 main함수의 a,b의 주소를 통하여 직접적으로 접근이 가능합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
void swap(int *px, int *py);
 
int main()
{
    int a = 100, b = 200;
 
    printf("a=%d b=%d\n", a, b);
    swap(&a, &b);
    printf("a=%d b=%d\n", a, b);
    return 0;
}
 
void swap(int *px, int *py)    // sawp(&a, &b)의 변수의 주소가 직접 전달된다.
{
    int tmp;
    
    tmp = *px;
    *px = *py;
    *py = tmp;
 
}
cs

위와같이 포인터를 통하여 매개변수를 정해주고 인수로 &a, &b로 해주게되면 변수의 주소가 직접 전달되기때문에 swap함수에서 값을 변경하면 주소에 직접 접근해서 값을 바꿀수 있게됩니다.




포인터 사용의 장점


1. 참조에 의한 호출

     - 외부의 변수나 배열에 직접 접근하여서 값을 변경 할 수 있다. 

2. 동적 메모리 할당

      - 동적 메모리 할당이 가능하게되어 메모리를 실시간으로 할당받을 수 있는 중요한 기법이 가능하다.

'C 프로그래밍 > 9. 포인터 ' 카테고리의 다른 글

9.1 포인터  (0) 2019.06.18

메모리의 주소를 가지고 있는 변수입니다. 컴퓨터의 메모리에는 바이트 단위로 주소가 매겨져있는데 이 주소를 이용하여 접근이 가능합니다.

포인터를 알아보기 전에 변수의 주소에 대해서 알아보겠습니다.



변수는 컴퓨터 메모리에 저장된다.


지금까지 우리는 변수를 만들어서 사용해 왔습니다. 이런 변수는 모두 메모리에 만들어집니다. 이러한 메모리에는 각 바이트마다 고유한 주소가 존재합니다. 우리는 이 주고를 이용하여 메모리 바이트에 접근이 가능합니다. 만약 시스템이 20바이트의 메모리를 가지고 있다면, 첫 번째 바이트의 주소는 0부터 시작해서 19까지의 주소가 존재합니다.


프로그램에서 변수를 만들면 컴파일러에 의해여 메모리 공간을 차지합니다. 전에 배웠듯이 변수에 따라서 메모리공간이 다른건 아실껍니다.



주소 연산자 &


C언어에서는 변수의 주소를 계산하는 연산자 &가 존재합니다. 주소 연산자 &는 변수의 이름을 받아서 변수의 주소를 반환합니다.

예를 들어서

1
int i; 라고 정의하였으면, 변수 i의 주소는 &i를 하면 알 수있다. 
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
 
int main()
{
    int i = 10;
    char c = 69;
    double f = 12.3;
    
    printf("i의 주소: %u\n"&i);
    printf("c의 주소: %u\n"&c);
    printf("f의 주소: %u\n\n"&f);
 
    printf("i의 주소: %x\n"&i);
    printf("c의 주소: %x\n"&c);
    printf("f의 주소: %x\n"&f);
}
cs



포인터의 선언


point + er 가리키는 것입니다.. 포인터는 변수의 주소를 가지고 있는 변수입니다. 같은 변수이지만 저장하고 있는 것은 데이터가 아닌 메모리의 주소입니다. 이것뺴고는 변수와 거의 동일하기 때문에 초기화를 해줘야합니다.


포인터를 선언하려면 포인터가 가리키게되는 대상을 쓰고 *을 붙인 다음, 포인터의 이름을 씁니다. 수식과는 아무 상관이 없습니다.

1
2
3
4
5
int *p;
 
int == 정수를
* == 가리키는
== 포인터 p
cs



포인터의 초기화


1
2
3
int i = 10// 정수 변수i가 선언되고 10으로 초기화된다/.
int *p; // 정수 포인터가 선언된다.
= &i; //포인터p에 i의 주소가 저장된다.
cs

이런식으로 해주면 됩니다. 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
 
int main()
{
    int i = 10;
    double f = 12.3;
    int *pi = NULL;
    double *pf = NULL;
 
    pi = &i;
    pf = &f;
    printf("%u %u\n", pi, &i);
    printf("%u %u\n", pf, &f);
    return 0;
}
cs

컴퓨터 마다 주소는 달라지지만 포인터를 이용하여 정상적으로 주소를 출력한 것을 볼수 있습니다.



간접 참조 연산자 *


앞서 &는 주소를 반환한다고 말했습니다. 간접 참조 연산자*는 p가 가리키는 주소에 저장된 내용을 읽어옵니다.

1
2
3
4
int i = 10// 정수 변수i가 선언되고 10으로 초기화된다/.
int *p; // 정수 포인터가 선언된다.
= &i; //포인터p에 i의 주소가 저장된다.
printf("%d \n"*p);  //10이 출력된다.
cs

*p는 p가 가리키는 위치에 있는 데이터를 가져오라는 의미입니다. p는 p가 가리키는 위치에 무엇이 있는지 모르기때문에, p가 int형 포인터라면 4바이트를 읽어들입니다. 포인터의 타입이 없다면, 포인터를 이용하여 데이터를 읽어 들일 때 몇개의 바이틀르 읽어야 할지 알 수 없게 됩니다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/
 
#include <stdio.h>
 
int main()
{
    int i = 3000;
    int*= NULL;
 
    p = &i;
 
    printf("p=%u\n", p);
    printf("&i=%u\n\n"&i);
 
    printf("i=%d\n", i);
    printf("*p=%d\n\n"*p);
 
 
    return 0;
}
cs

사용자마다 메모리 주소는 다릅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*변수와 포인터를 연결한 후에 변수의 주소와 포인터의 값을 출력.*/
 
#include <stdio.h>
 
int main()
{
    int i = 3000;
    int*= NULL;
 
    p = &i;
 
    printf("p=%u\n", p);
    printf("&i=%u\n\n"&i);
 
    printf("i=%d\n", i);
    printf("*p=%d\n\n"*p);
 
 
    return 0;
}
cs



포인터 사용지 주의할 점


-초기화 하지 않기

쓰레기 값을 가지기때문에 꼭 초기화를 해줘야 합니다.



-NULL포인터의 사용

포인터가 아무것도 가리키고 있지 않을 때는 NULL로 설정해주세요. NULL은 0을 뜻합니다.


-포인터 타입과 변수의 타입은 일치해야한다.

포인터도 여러가지 타입이 존재하는데 포인터의 타입에 따라 메모리를 얼만큼 읽어들이는지 달라지기때문에 꼭 일치해야합니다.


- 절대 주소 사용

윈도우에서는 절대 주소를 사용하지 말아주세요.,




포인터의 연산


덧셈과 뺼셈 연산

포인터에서 p++하게되면 포인터의 정수형 만큼 ++가 됩니다. int 형이면 1이 늘어나는것이 아닌 4만큼 늘어나고, 

double형이면 8만큼 늘어나게 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <stdio.h>
 
int main()
{
    char *pc;
    int *pi;
    double *pd;
 
    pc = (char *)10000;
    pi = (int *)10000;
    pd = (double *)10000;
 
    printf("증가 전 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 현재 값
 
    pc++;
    pi++;
    pd++;
    printf("증가 후 pc = %d , pi = %d , pd = %d\n", pc, pi, pd); // 1씩 더한 값
 
    printf("      pc+2 = %d , pi+2 = %d , pd+2 = %d\n", pc + 2, pi + 2, pd + 2); // 2씩 더한 값
 
    return 0;
}
cs






지금 까지 배워온 배열은 X좌표만 존재한다고 생각할 수 있습니다.

이번에는 배열을 X,Y좌표로 저장한다고 생각하면 쉽습니다.


int s[3][5]; 라고 선언을 하게되면


 

0열 

1열 

2열 

3열 

4열 

 0행

 s[0][0]

 s[0][1]

 s[0][2] 

 s[0][3] 

 s[0][4] 

 1행

 s[1][0] 

 s[1][1] 

 s[1][2] 

 s[1][3] 

 s[1][4] 

 2행

 s[2][0] 

 s[2][1] 

 s[2][2] 

 s[2][3] 

 s[2][4] 

행과 열로 이야기를 하면 배열 s는 3개의 행으로 이루어졌고 각 행에는 5개의 요소가 있다고 할 수 있습니다.



2차원 배열에서의 요소 참조


참조를 위해서는 2개의 인덱스가 필요합니다. 

2차원 배열의 요소에 값을 저장하기 위해서는 변수 i는 0행에서 i-1행까지 변경시키고, 변수j는0에서 j-1까지 변경시키면서 s[i][j]에 저장하면 됩니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <stdlib.h>
#define ROWS 3
#define COLS 5
 
int main()
{
    int s[ROWS][COLS];
    int i,j;
 
    for ( i = 0; i < ROWS; i++)
    {
        for ( j = 0; j < COLS; j++)
        {
            s[i][j] = rand() % 100;
        }
    }
    for ( i = 0; i < ROWS; i++)
    {
        for ( j = 0; j < COLS; j++)
        {
            printf("%02d ", s[i][j]);
        }
        printf("\n");
    }
    return 0;
}
cs

2차원 배열에서의 요소 참조실행 결과



2차원 배열의 초기화


당연히 선언과 동시에 초기화가 가능합니다. 다만 같은 행에 속하는 초기값들을 중괄호로 묶어줘야합니다.

1
2
3
4
5
    int a[3][5] = {
        {87,98,80,76,3},
        {99,89,90,90,0},
        {65,68,50,49,0}
    };
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*학생들의 성적 기록표를 2차원 배열에 저장하고 각 학생의 최종 성적을 계산해보자.*/
 
 
#include <stdio.h>
#define ROWS 3
#define COLS 5
 
int main()
{
    int a[ROWS][COLS] = {
        {87,98,80,76,3},
        {99,89,90,90,0},
        {65,68,50,49,0}
    };
 
    int i;
 
    for ( i = 0; i < ROWS; i++)
    {
        double final_scores = a[i][0* 0.3 + a[i][1* 0.4 + a[i][2* 0.2 + a[i][3* 0.1 - a[i][4];
        printf("학생 #%i의 최종 성적 = %10.2f \n", i + 1, final_scores);
    }
    return 0;
}
cs

성적 기록표실행 결과


행렬의 합
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <stdio.h>
#define ROWS 3
#define COLS 3
 
int main()
{
    int A[ROWS][COLS] = {
        {2,3,0},
        {8,9,1},
        {7,0,5}
    };
    int B[ROWS][COLS] = {
        { 1,0,0},
        { 1,0,0},
        { 1,0,0}
    };
    int C[ROWS][COLS];
 
    int r, c;
 
    for ( r = 0; r < ROWS; r++)
    {
        for ( c = 0; c < COLS; c++)
        {
            C[r][c] = A[r][c] + B[r][c];
        }
    }
    for ( r = 0; r < ROWS; r++)
    {
        for ( c = 0; c < COLS; c++)
        {
            printf("%d ", C[r][c]);
        }
        printf("\n");
    }
    return 0;
}
cs

행렬의 합실행 결과


2차원 배열을 함수로 전달하기


함수에 인수로 전달이 가능합니다. 원본이 전달됩니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#define YEARS 3
#define PRODUCTS 5
 
int sum(int scores[YEARS][PRODUCTS]);
 
int main()
{
    int sales[YEARS][PRODUCTS] = { {1,2,3},{4,5,6},{7,8,9} };
    int total_sale;
 
    total_sale = sum(sales);
    printf("총 매출은 %d입니다. \n", total_sale);
 
    return 0;
}
 
int sum(int scores[YEARS][PRODUCTS])
{
    int y, p;
    int total = 0;
 
    for ( y = 0; y < YEARS; y++)
    {
        for ( p = 0; p < PRODUCTS; p++)
        {
            total += scores[y][p];
        }
    }
    return total;
}
cs




tic tac toe 게임


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
 
int main()
{
    char board[3][3];
    int x, y, k, i;
 
    //보드 초기화
    for ( x = 0; x < 3; x++)
    {
        for ( y = 0; y < 3; y++)
        {
            board[x][y] = ' ';
        }
    }
 
    // 사용자로부터 위치를 받아서 보드에 표시
    for ( k = 0; k < 9; k++)
    {
        printf("(x, y) 좌표: ");
        scanf(" %d %d"&x, &y);
        board[x][y] = (k % 2 == 0) ? 'x' : '0'// 현재의 순번에 따라 x,0 중 선택
 
        for ( i = 0; i < 3; i++// 보드를 화면에 그린다.
        {
            printf("---|---|---\n");
            printf("%c  | %c | %c \n", board[i][0], board[i][1], board[i][2]);
        }
        printf("---|---|---\n");
    }
    return 0;
}
cs

실행결과는 알아서 연구해보세요.

'C 프로그래밍 > 8. 배열' 카테고리의 다른 글

8.3 정렬과 탐색  (0) 2019.06.18
8.2 배열과 함수  (0) 2019.06.18
8.1 배열이란?, 배열의 초기화  (0) 2019.06.18

정렬은 물건을 크기순으로 오름차순또는 내림차순으로 나열하는 것을 의미합니다. 컴퓨터 공학 분야에엇 가장 기본적이고 중요한 알고르즘 중의 하나로 일상생활에서 많이 이용됩니다.

컴퓨터도 정렬을 하지않으면 탐색의 효율성이 크게 떨어지게됩니다.



선택 정렬


두 개의 배열이 있다고 가정하면 오른쪽 배열에서 가장 작은 숫자를 선택하여 왼쪽 배열로 이동시키는 작업을 오른쪽 정렬이 공백 상태가 될때 까지 반복하는 정렬 기법이다.


 왼쪽 배열

오른쪽 배열 

설명 

() 

(5,3,8,1,2,7)

 초기상태

(1) 

 (5,3,8,2,7)

 1선택

(1,2) 

(5,3,8,7) 

2선택 

(1,2,3) 

(5,8,7) 

3선택 

(1,2,3,4) 

(8,7) 

4선택 

(1,2,3,4,5) 

(8) 

5선택 

(1,2,3,4,5,6) 

() 

6선택 



또다른 방법이 있다. 배열에서 최소값을 탐색한 당ㅁ 이 최소값을 배열의 첫 번쨰 원소와 교환하고 두번째원소에 그다음 작은값을 넣는 방법이다.

이 방법은 배열이외에 여분의 변수가 필요하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*선택 정렬*/
 
#include <stdio.h>
#define SIZE 10
 
int main()
{
    int list[SIZE] = { 3,2,9,7,1,4,8,0,6,5 };
 
    int i, j, temp, least;
 
    for ( i = 0; i < SIZE-1; i++)
    {
        least = i;
        for ( j = i+1; j < SIZE; j++)
        {
            if (list[j]<list[least])
            {
                least = j;
            }
        }
        temp = list[i];
        list[i] = list[least];
        list[least] = temp;
    }
    for ( i = 0; i < SIZE; i++)
    {
        printf("%d ", list[i]);
    }
    printf("\n");
    return 0;
}
 
cs

실행 결과 : 0 1 2 3 4 5 6 7 8 9




탐색


컴퓨터가 가장 많이 하는 작업중 하나이다.

순차 탐색과 이진 탐색으로 나뉜다.



순차 탐색


가장 간단하고 직접적인 탐색 방법이다. 배열의 원소를 하나씩 꺼내서 탐색키와 비교하여 원하는 값을 찾아가는 방법이다.

일치하는 항목을 찾을떄 까지 비교를 계속한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*순차 탐색*/
 
#include <stdio.h>
#define SiZE 10    
 
int main()
{
    int key, i;
    int list[SiZE] = { 1,2,3,4,5,6,7,8,9 };
 
    printf("탐색할 값을 입력하시오 : ");
    scanf("%d"&key);
 
    for ( i = 0; i < SiZE; i++)
    {
        if (list[i] == key)
        {
            printf("탐색 성공 인덱스= %d\n", i);
        }
    }
    printf("탐색 종료\n ");
    return 0;
}
cs



이진 탐색


속도가 빠른 탐색 기법이다. 대신에 배열이 정렬이 되어 있어야한다.


중앙에 있는 값을 탐색키와 비교한후 일치하면 찾은 것이고 탐색키가 중앙 원소값보다 작으면 배열의 전반부에 값이 있기떄문에 후반부는 탐색의 범위에서 제외한다. 이런식으로 탐색을 하다보면 찾을수 있게된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <stdio.h>
#define SIZE 16
int binary_search(int list[], int n, int key);
 
int main()
{
    int key;
    int grade[SIZE] = { 2,6,11,13,18,20,22,27,29,30,34,38,41,42,45,47 };
 
    printf("탐색할 값을 입력하시오 ");
    scanf("%d"&key);
    printf("탐색 결과 = %d\n", binary_search(grade, SIZE, key));
 
    return 0;
}
 
int binary_search(int list[], int n, int key)
{
    int low, high, middle;
 
    low = 0;
    high = n - 1;
 
    while (low<=high)                     // 아직 숫자들이 남아있으면
    {
        printf("[%d %d]\n", low, high);  // 하한과 상한을 출력한다.
        middle = (low + high) / 2;       //중간 위치를 계산한다
        if (key==list[middle])          //일치하면 탐색 성공
        {
            return middle;
        }
        else if (key>list[middle])     //중간 원소보다 크다면
        {
            low = middle + 1;          //새로운 값으로 low를 설정
        }
        else
        {
            high = middle - 1;        //새로운 값으로 high를 설정
        }
 
    }
    return -1;
}
cs


'C 프로그래밍 > 8. 배열' 카테고리의 다른 글

8.4 2차원 배열  (0) 2019.06.18
8.2 배열과 함수  (0) 2019.06.18
8.1 배열이란?, 배열의 초기화  (0) 2019.06.18

당연하겠지만 배열도 함수로 전달이 가능합니다.

하지만 배열은 값에의한 호출이 아닌 원본 그대로 전달된다는것을 알아야됩니다.

이에 대해서는 포인터를 배워야되니 원본이 전달된다는것만 알아두세요.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*학생들의 성적을 저장하고 있는 정수 배열을 만들고 평균을 계산하는 함수를 작성*/
 
#include <Stdio.h>
#define STUDENTS 5
 
int get_avg(int scores[], int size); //1 , 원형을 정의. 배열을 받는 매개변수는 크기를 적어주지 않아도됨.
int main()
{
    int sco[STUDENTS] = { 1,2,3,4,5 };
    int avg;
 
    avg = get_avg(sco, STUDENTS);
    printf("평균은 %d입니다.\n", avg);
 
    return 0;
}
//배열에 들어 있는 값들의 평균 계산
int get_avg(int scores[], int size//2  scores[] 원본 배열이 전달
{
    int i;
    int sum = 0;
 
    for ( i = 0; i < size; i++)  // 반복하면서 배열의 모든 요소들의 합을 계산.
    {
        sum += scores[i];
    }
    return sum / size;
}
 
cs




원본 배열의 변경


앞서 말했다시미 원본배열이 바뀐다고 하였습니다.

매개 변수를 통하여 원본을 참조하기때문에 항상 조심하여야됩니다. 만약 함수 안에서 매개 변수를 통하여 배열 요소를 변경한다면 이것은 원본 배열을 변경시키는 결과가 나옵니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/*원본 배열의 변경, 1차원 배열을 조작하는 함수*/
 
#include <stdio.h>
#define SIZE 7
 
void modify_array(int a[], int size);
void print_array(int a[], int size);
 
int main()
{
    int list[SIZE] = { 1,2,3,4,5,6,7 };
 
    print_array(list, SIZE);
    modify_array(list, SIZE);
    print_array(list, SIZE); // 원본이 전달
 
    return 0;
}
// a[]를 변경하면 원본이 변경된다.
void modify_array(int a[], int size// modify_array()는 배열을 인수로 받아서 배열내의 모든 요소를 하나 증가. 
배열은 원본이 전달되므로, 호출된 함수가 배열의 요소를 수정하면 원본 배열의 내용도 동시에 수정

//const int 함수를 사용시 컴파일 에러가 뜬다(수정을 못함)
{
    int i;
 
    for (i = 0; i < size; i++)
    {
        a[i]=a[i]*a[i];
    }
 
}
// 배열 요소들을 출력
void print_array(int a[], int size)
{
    int i;
 
    for (i = 0; i < size; i++)
    {
        printf("%3d", a[i]);
    }
    printf("\n");
}
 
cs


원본 배열의 변경을 금지시키려면 앞에 배운 const지정자를 사용하면 된다.

'C 프로그래밍 > 8. 배열' 카테고리의 다른 글

8.4 2차원 배열  (0) 2019.06.18
8.3 정렬과 탐색  (0) 2019.06.18
8.1 배열이란?, 배열의 초기화  (0) 2019.06.18

지금까지 학습하였던 변수는 하나의 값만을 저장할 수 있었지만, 배열을 이용하면 많은 값을 한꺼번에 저장이 가능합니다. 배열을 사용하면 한 번에 여러 개의 변수를 생성하는하고 이는 연속된 메모리 주소에 저장됩니다.



배열이 필요한 이유


학생이 10명이 있다고 가정하면, 10개의 변수가 필요한데,

1
int s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10;
cs

이렇게 선언을 해야합니다.

그러나, 이러한 학생이 30명, 300명을 넘어간다고치면, 10000명을 넘어가면 프로그래머 생활이 아주 힘들어질껍니다.

이를 위해 탄생한 것이 배열이며, 배열을 이용하면 같은 종류의 대량의 데이터를 효율적이고 간편하게 처리할 수 있습니다.


배열 안에 들어있는 데이터는 정수로 되어 있는 번호에 의하여 접근됩니다.

1
int s[10];
cs

배열을 선언한겁니다. 저렇게 쳐주면 연속된 메모리 주소에 s[0]~s[9]까지 자동으로 생성됩니다.

이러한 배열에는 순차적인 번호가 부여되는데 이것을 인덱스라고합니다.



배열의 특징


- 배열은 메모리의 연속적인 공간에 저장된다. 

ex) s[0]과 s[1]은 실제 메모리에서도 서로 붙어있다.


- 관련된 데이터를 차레로 접근하여서 처리가 가능하다. 하나의 이름을 공유하고 번호만 다를 뿐이라면 편리하게 사용 가능해진다.




배열의 선언


배열을 사용하려면 먼저 배열을 선언하여햐 합니다. 배열 선언을 통하여 컴파일러에게 요소의 개수과 자료형이 무엇인지를 알려줍니다. 

1
int scores[10];
cs

배열 선언이 완료되었습니다. int형으로 scores라는 이름으로 10개의 요소를 선언하였습니다. 선언을 하면 메모리에는

1
scores[0],scores[1],scores[2],scores[3],scores[4],scores[5],scores[6],scores[7],scores[8],scores[9],
cs

이렇게 저장됩니다.


다양한 배열 선언으로 감을 잡아봅시다.


1
2
3
4
float cost[12]; // 12개의 float형 값을 가지는 배열 cost
char name[50]; // 50개의 char형 값을 가지는 배열 name
char src[10], dst[10//2개의 문자형 배열 src와 dst를 동시에 선언
int index, days[7//일반 변수 index와 배열 days를 동시에 
cs



주의사항


1. 배열의 크기는 꼭 지정해줘야합니다.

2. 배열의 크기를 변수로 할수는 없습니다.

3. 배열의 크기가 음수이면 안됩니다.

4. 배열의 크기가 실수이면 안됩니다.




배열 요소 접근


인덱스라는 번호를 사용하여 접근합니다.

예를 들어 scores배열에서 인덱스가 5인 요소에 접근하려면 scores[5]와같이 적어주면 됩니다.

1
scores[7= 4;
cs



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//배열을 선언하고 배열 요소에 값을 대입하는 기초적인 예제부터 살펴보자.
 배열 요소를 차례대로 처리할 때 유용하게 사용되는 것이 for반복문이다.
 
#include <stdio.h>
int main()
{
    int i;
    int score[5];
    score[0= 10;
    score[1= 20;
    score[2= 30;
    score[3= 40;
    score[4= 50;
 
    for (i = 0; i < 5; i++)
    {
        printf("grade[%d]=%d\n", i, score[i]);
    }
    return 0;
}
cs

배열고 반복문

1
2
3
4
for (int i = 0; i < 5; i++)
{
    scores[i] = 0;
}
cs

이런식으로 반복문을 이용하여 배열에 값을 쉽게 넣을수도 있다.



인덱스의 범위

scores[5]라고 선언하였으면 사용할 수 있는 인덱스의 범위는 0~4까지이다. 이를 넘어가게되면 심각한 오류가 발생하니 주의 하여야한다.



배열의 초기화


배열을 초기화 하는 방법은 다음과 같다.


1
2
3
4
5
6
7
8
9
10
11
12
int scores[5]={10,20,30,40,50// 인덱스 0부터 4까지 순차적으로 저장된다.
 
int scores[5]={10,20,30// 인덱스 0부터 2까지 순차적으로 저장하고 나머지부분은 0으로 초기화한다. 
이를 이용해서 int scores[5]={0};//을 치게되면  0~4까지 모두 0으로 초기화하게된다.
 
int scores[]={10,20,30,40,50}; // 배열의 크기가 주어지지않을경우 최값의 개수가 배열의 크기가 된다.
 
int scores[5];             //인덱스 0~4까지 모두 쓰레기값이 들어간다.
 
 
 
 
cs



배열의 요소의 개수는 sizeof()를 통해서 가능하다.



배열의 복사


배열의 복사는 

1
2
int a[5]={12345};
int b[5];
cs

와 같이하면 복사되지않는다.

for반복문을 이용해서 인덱스마다 1개씩 일일이 복사해줘야한다.

1
2
3
4
5
6
7
int a[5]={12345};
int b[5];
 
for(i = 0; i < 5; i++)
{
    b[i] = a[i];
}
cs



배열의 비교


배열의 복사처럼 for문을 이용해서 하나씩 비교해줘야한다.

1
2
3
4
5
6
7
8
9
10
int a[5= { 1,2,3,5,4 };
int b[5= { 1,2,3,5,4 };
 
for ( i = 0; i < 5; i++)
{
    if (a[i]!=b[i])
    {
        printf("다름");
    }
}
cs





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
 
#define SEAT 10
 
int main()
{
    char inp1;
    int inp2, i;
    int seats[SEAT] = { 0 };
 
    while (1)
    {
        printf("좌석을 예약하시겠습니까? (y,n)");
        scanf("%c%*C"&inp1);
 
        if (inp1=='n')
        {
            break;
        }
 
        printf("===========================\n");
        for ( i = 1; i <= SEAT; i++)
        {
            printf(" %d", i);
        }
        printf("\n");
        printf("===========================\n");
 
        for ( i = 0; i < SEAT; i++)
        {
            printf(" %d", seats[i]);
        }
        printf("\n");
 
        printf("예약할 좌석을 입력해주세요.");
        scanf("%d"&inp2);
        if (seats[inp2-1]==0)
        {
            seats[inp2 - 1= 1;
            printf("예약되었습니다.");
        }
        else
        {
            printf("이미 예약된 좌석입니다.");
        }
 
        
    }
return 0;}
cs

한번 분석해보고 직접 컴파일 해보자.

'C 프로그래밍 > 8. 배열' 카테고리의 다른 글

8.4 2차원 배열  (0) 2019.06.18
8.3 정렬과 탐색  (0) 2019.06.18
8.2 배열과 함수  (0) 2019.06.18