• 검색 결과가 없습니다.

11차시: 함수 동적 메모리 할당 다차원 배열

N/A
N/A
Protected

Academic year: 2022

Share "11차시: 함수 동적 메모리 할당 다차원 배열"

Copied!
41
0
0

로드 중.... (전체 텍스트 보기)

전체 글

(1)

11차시:

함수

동적 메모리 할당 다차원 배열

프로그래밍 및 실험

제 11주

동국대학교 조영석

이 문서는 나눔글꼴로 작성되었습니다. 설치하기

(2)

6.6 함수 인자로써의 배열

- 함수정의에서 배열로 선언된 형식 매개 변수는 pointer임.

- 함수의 인자로 배열이 전달되면 배열의 기본 주소가 (배열의 내용이 아님) call-by-value로 전달됨.

- 배열 원소는 복사되지 않음.

(3)

3

(예)

#include <stdio.h>

double sum(double *, int);

void main( ) {

double D[5] = {3.5, 4.5, 5.5, 6.5}; /* D[4] == 0.0 */

int n = 5, i;

for (i = 0, i < n; ++i)

printf("%lf", *(D + i));

printf("\n%lf", sum(D, n));

}

double sum(double a[], int n) { /* n is the size of a[] */

int i; /* double a[] == double *a */

double sum = 0.0; /* 변수이름 = 함수이름, but O.K. */

for (i = 0; i < n; ++i) sum = sum + a[i];

return sum;

} 실행결과 : 3.5 4.5 5.5 6.5 0.0

20.0

(4)

sum( )이 호출되는 여러 방법

호출 계산 및 리턴되는 값

sum(v, 100) v[0] + v[1] + ... + v[99]

sum(v, 88) v[0] + v[1] + ... + v[87]

sum(&v[7], k - 7) v[7] + v[8] + ... + v[k - 1]

sum(v + 7, 2 * k) v[7] + v[8] + ... + v[2 * k + 6]

(5)

5

6.7 예제 : 버블정렬

void swap(int *, int *);

void bubble(int a[], int n) {

int i, j;

for (i = 0; i < n - 1; ++i) for (j = n - 1; j > i; --j) if (a[j - 1] > a[j])

swap(&a[j - 1], &a[j]);

}

(6)

int a[] = {7, 3, 66, 3, -5, 22, -77, 2};

bubble(a, 8); a[j-1] > a[j]?

i = 0, j = 7 a[6] v.s. a[7]

i = 0, j = 6

a[5] v.s. a[6]

i = 0, j = 5

a[4] v.s. a[5]

i = 0, j = 4

a[3] v.s. a[4]

i = 0, j = 3

a[2] v.s. a[3]

i = 0, j = 2

a[1] v.s. a[2]

i = 0, j = 1

a[0] v.s. a[1]

(7)

7

i = 1, j = 7 a[6] v.s. a[7]

: :

: :

i = 7, j = 2

a[1] v.s. a[2]

i = 2, j = 7 a[6] v.s. a[7]

: :

: :

i = 7, j = 3

a[2] v.s. a[3]

i = 3, j = 7 a[6] v.s. a[7]

: :

: :

i = 7, j = 4

a[3] v.s. a[4]

: :

i = 6, j = 7 a[6] v.s. a[7]

i = 7, j = 7 실행종료

(8)

8

0 1 2 3 4 5 6 7

i j

i j

i j

i j

i j :

:

종료.

(9)

9

algorithm의 효율성 분석: 비교 횟수

for (i = 0; i < n - 1; ++i) for (j = n - 1; j > i; --j) if (a[j - 1] > a[j])

swap(&a[j - 1], &a[j]);

i의 변화: 0 부터 (n-2)까지 (n-1)회

j의 변화: (n-1)부터 (i+1)까지 (n-2)+(n-3)+(n-4)+…+1회

= (n-2)(n-1)/2 = (n2-3n+2)/2 ≈ n2 =

O

(n2)

n(자료의 개수)가 늘어나면 시간복잡도(time complexity)가 크게 증가

(10)

6.8 calloc( )과 malloc( )을 이용한 동적 메모리 할당 (dynamic memory allocation)

- 표준 library에 제공.

- prototype은 stdlib.h에 포함됨.

- calloc( ) : Contiguous Allocation.

calloc(n, el_size)

• 각 원소가 el_size인 n개의 원소로 이루어진 배열.

• memory 영역은 모든 bit가 0으로 초기화 됨.

• void * 형의 pointer가 return됨.

(또는 NULL이 return됨. - 실패했을 경우)

(11)

11

- malloc( ) : Memory Allocation.

malloc(memory_size)

• memory의 초기화 않음.

• calloc( )보다 시간이 적게 걸림.

• void * 형의 pointer(또는 NULL)가 return됨.

-

free(ptr)

• 동적으로 할당받은 공간은 함수의 실행이 끝나도 system 에 반환되지 않으므로 반드시 명시적으로 반환할 것.

(12)

12

(예)

#include <stdio.h>

#include <stdlib.h>

int main( ) {

int *a;

int n;

....

a = calloc(n, sizeof(int)); /* machine independent */

....

free(a);

}

또는 ,

a = malloc(n * sizeof(int));

(13)

13

6.9 예제 : 합병(merge)과 합병정렬(merge sort) - 두개의 정렬된 array a[]와 b[]를 이용하여

하나의 정렬된 array c[]를 만드는 방법.

• a[i]와 b[j]를 비교하여 작은 수를 c[k]에 저장하고 작은쪽의 index와 c[]의 index를 하나씩 증가시킴.

• a[], b[] 어느 한쪽의 index가 범위를 넘으면 (즉, 모두 c[]로 옮겨지면) 다른 array의 나머지 element를 모두 순 서대로 c[]에 옮김.

a

a[i]

0 1 2 .... M-1

b

b[j]

0 1 2 .... N-1

c

c[k]

0 1 2 ... ... N+M-2

(14)

File "mergesort.h"의 내용.

#include <assert.h>

#include <stdio.h>

#include <stdlib.h>

void merge(int a[], int b[], int c[], int m, int n);

void mergesort(int key[], int n);

void wrt(int key[], int sz);

(15)

15

File "merge.c"의 내용.

#include "mergesort.h"

void merge(int a[], int b[], int c[], int m, int n) {

int i = 0, j = 0, k = 0;

while (i < m && j < n) if (a[i] < b[j])

c[k ++] = a[i++];

else

c[k++] = b[j++];

while (i < m)

c[k++] = a[i++];

while (j < n)

c[k++] = b[j++];

}

(16)

16

File "mergesort.c"의 내용.

#include "mergesort.h"

void mergesort(int key[], int n) {

int j , k, m, *w;

for (m = 1; m < n; m = m * 2) ;

if (n < m) {

printf(" \nERROR : Array size must be a power of 2.\n");

exit(1);

}

w = calloc(n, sizeof(int));

assert(w != NULL);

for (k = 1; k < n; k = k * 2) {

for (j = 0; j < n - k; j = j + 2 * k)

merge(key + j, key + j + k, w + j, k, k);

for (j = 0; j < n; ++j) key[j] = w[j];

}

free(w);

}

(17)

17

n = 8의 경우

merge(key+j, key+j+k, w+j, k, k);

k j(=j+2k) n-k function call .

1 0 7 merge(key+0, key+0+1, w+0, 1, 1); A

1 2 7 merge(key+2, key+2+1, w+2, 1, 1); B 1 4 7 merge(key+4, key+4+1, w+4, 1, 1); C 1 6 7 merge(key+6, key+6+1, w+6, 1, 1); D

key

0 1 2 3 4 5 6 7

A B C D

(18)

k j(=j+2k) n-k function call .

2 0 6 merge(key+0, key+0+2, w+0, 2, 2); A

1 4 7 merge(key+4, key+4+2, w+4, 2, 2); B

k j(=j+2k) n-k function call .

4 0 4 merge(key+0, key+0+4, w+0, 4, 4); A key

0 1 2 3 4 5 6 7

A B

key

0 1 2 3 4 5 6 7

A

(19)

19

합병정렬의 효율성 분석:

- array(data)의 크기가 2의 거듭제곱인 경우에 효율적 - data 비교횟수 분석: N = 32 = 25의 경우

k=1 (1:1) 16set(1회(≈2)/set 비교) 비교횟수≤32회 k=2 (2:2) 8set(max 3회(≈4)/set) 비교횟수≤32회 k=4 (4:4) 4set(max 7회(≈8)/set) 비교횟수≤32회 k=8 (8:8) 2set(max 15회(≈16)/set) 비교횟수≤32회 k=16 (16:0) 정렬완료

외부 loop: 4회(≈5회; log2 32 = log2 25 = 5 log2 2 = 5) 내부 loop: ≈32회 비교(= N)

총 loop횟수: ≤ 5 * 32 (= log2N * N = N log2 N)

time complexity:

O

(n log n): Bubble Sort에 비해 매우 양호

(20)

20

6.10 문자열

- char형의 1차원 배열.

- 문자열은 '\0'(NULL)로 끝남.

- 문자열의 크기는 '\0'를 포함하며 가변임.

(예) "abc" : 크기 = 4, 마지막 element = '\0' - char *p = "abc"; /* char *p; p = "abc"; */

printf("%s %s\n", p, p + 1);

실행결과 : abc bc

• p는 문자열 "abc"의 'a'의 주소 값을 가짐.

• printf()는 p에서 시작하여 '\0'의 직전까지 print.

- 문자열 상수는 pointer로 취급됨.

"abc"[1] == 'b'

*("abc" + 2) == 'c'

(21)

21

- char *p = "abcde";

char s[] = "abcde";

임시 memory 영역 (예) 문자열 내의 단어의 수를 세는 program.

#include <stdio.h>

#include <ctype.h>

int word_count (const char *a);

void main() {

char *s = "Mary had a little lamb.";

printf("\n%s\n",

s);

printf("\nNumber of words : %d", word_count(

s));

}

a b c d e \0 s

a b c d e \0 p

(22)

22

int word_count (const char *s) {

int count = 0;

while (*s != '\0') {

while( isspace(*s) ) /* skip space */

++s;

if (*s != '\0') { /* found a word */

++ count;

while (!isspace(*s) && *s != '\0')

++s; /* skip the word */

} }

return count;

}

(23)

23

6.11 표준 라이브러리에 있는 문자열 조작 함수(string.h) - char *strcat(char *s1, const char *s2);

• 두개의 문자열 s1과 s2를 결합하여 s1에 결과 저장.

• s1은 결과를 저장할 수 있을 만큼의 충분한 공간을 point할 수 있도록 해야 함.

• 문자열 s1이 return 됨.

char *strcat(char *s1, register const char *s2) {

register char *p = s1;

while (*p) /* go to the end */

++p;

while (*p++ = *s2++) /* copy */

;

return s1;

}

(24)

- int strcmp(const char *s1, const char *s2);

• 두 문자열이 인자로 전달됨.

• s1과 s2를 사전적 순서로 비교하여

s1이 작으면 음수, 크면 양수, 같으면 0을 return.

(25)

25

- char *strcpy(char *s1, const char *s2);

• 문자열 s2를 '\0'이 나올때까지 s1에 복사.

• s1의 내용은 s2의 내용으로 overwrite 됨

• s1에 충분한 공간이 마련되어야 함.

• pointer s1이 return됨.

char *strcpy(char *s1, register const char*s2) {

register char *p = s1;

while(*p++ = *s2++)

; return s1;

}

(26)

- size_t strlen(const char *);

• '\0'을 제외한 문자의 개수를 returen.

• size_t는 부호없는 정수적 형.

• 4 bytes/word system에서는 unsigned int.

• 2 bytes/word system에서는 unsigned long.

size_t strlen(const char *s) {

size_t n;

for (n = 0; *s != '\0'; ++s) ++n;

return n;

}

(27)

27

선언 및 초기화

char s1[] = "beautiful big sky country", s2[] = "how now brown cow";

수식 값

strlen(s1) 25

strlen(s2 + 8) 9

strcmp(s1, s2) 음의 정수

문장 출력되는 값

printf("%s", s1+10); big sky country strcpy(s1 + 10, s2 + 8);

strcat(s1, "s!");

printf("%s", s1); beautiful brown cows!

(28)

6.12 다차원 배열

int a[100]; :일차원 배열 int b[2][7]; :이차원 배열 int c[5][3][2]; :삼차원 배열

(29)

29

- 2차원 배열

(예) int a[3][5];

- a[i][j]의 다른 표현

• *(a[i] + j)

• (*(a + i))[j]

• *((*(a + i)) + j)

• *(&a[0][0] + 5 * i + j)

1열 2열 3열 4열 5열

1행 a[0][0] a[0][1] a[0][2] a[0][3] a[0][4]

2행 a[1][0] a[1][1] a[1][2] a[1][3] a[1][4]

3행 a[2][0] a[2][1] a[2][2] a[2][3] a[2][4]

row(행) column(열)

(30)

형식 매개변수 선언

- 함수를 정의할 때 형식매개변수가 다차원 배열일 경우, 첫번째를 제외한 모든 크기를 명시해야 함.

(예) int a[3][5];

int sum(int a[][5]) {

int i, j, sum = 0;

for (i = 0; i < 3; ++i) for (j = 0; j < 5; ++j)

sum = sum + a[i][j];

return sum;

}

(31)

31

• 매개 변수의 다른 정의 : 함수 정의의 header에서만 동일함.

int a[][5]

int a[3][5] : 상수 3을 compiler는 무시 int (*a)[5]

(비교 : 1차원 배열) int b[]

int b[3]

int *b

(32)

32

- 초기화

int a[2][3] = {1, 2, 3, 4, 5, 6};

int a[2][3] = {{1, 2, 3}, {4, 5, 6}};

int a[][3] = {{1, 2, 3}, {4, 5, 6}};

• 내부 중괄호가 생략되면 a[0][0], a[0][1], a[0][2], a[1][0], a[1][1], a[1][2]의 순으로 초기화 함.

- typedef의 사용 #define N 3

typedef double scalar ; typedef scalar vector[N];

typedef scalar matrix[N][N];

(또는 typedef vector matrix[N];)

(33)

33

(예) void add(vector x, vector y, vector z) {

int i;

for (i = 0; i < N; ++i) x[i] = y[i] + z[i];

}

scalar dot_product(vector x, vector y) {

int i;

scalar sum = 0.0;

for (i = 0; i < N; ++i)

sum = sum + x[i] * y[i];

return sum;

}

(34)

void multiply (matrix a, matrix b, matrix c) {

int i, j, k;

for (i = 0; i < N; ++i) { for (j = 0; j < N; ++j) { a[i][j] = 0.0;

for (k = 0; k < N; ++k)

a[i][j] = a[i][j] + b[i][k] * c[k][j];

} } }

= *

(35)

35

6.13 포인터 배열 (예) char * w[5];

w[0] = "Mary";

w[1] = "had";

w[2] = "a";

w[3] = "little";

w[4] = "lamb.";

M a r y \0 h a d \0

a \0

l i t t l e \0 l a m b . \0

w[0] "Mary"

"had"

"a"

"little"

"lamb."

(36)

36

#include <stdio.h>

#define N 5 void main() {

char *w[N]; int i;

w[0] = "Mary"; w[1] = "had"; w[2] = "a";

w[3] = "little"; w[4] = "lamb.";

printf ("\n%s %s %s %s %s\n",

w[0], w[1], w[2], w[3], w[4]);

printf ("\n%s %s %s %s %s\n",

*w, *(w+1), *(w+2), *(w+3), *(w+4));

}

(37)

37

#include <stdio.h>

#define N 5 void main() {

char *w[N]; int i;

*w = "MARY"; *(w+1) = "HAD"; *(w+2) = "A";

*(w+3) = "LITTLE"; *(w+4) = "LAMB.";

for (i=0; i<N; ++i)

printf ("%s ", w[i]);

for (i=0; i<N; ++i)

printf ("%s ", *(w+i));

}

(38)

문자열 정렬

void sort_words(char *w[], int n) {

int i, j;

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

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

if (strcmp(w[i], w[j]) > 0) swap(&w[i], &w[j]);

}

void swap(char **p, char **q) {

char *tmp;

tmp = *p;

*p = *q;

*q = tmp;

}

(39)

39

6.14 main( ) 함수의 인자

#include <stdio.h>

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

int i;

printf("argc = %d\n", argc);

for (i = 0; i < argc; ++i)

printf("argv[%d] = %s\n", i, argv[i]);

}

my_echo 라는 이름의 실행 화일을 생성.

my_echo a is for apple.

(실행결과) argc = 5

argv[0] = my_echo argv[1] = a

argv[2] = is argv[3] = for

argv[4] = apple.

(40)

6.15 래기드 배열(ragged array) 6.16 인자로서의 함수

6.17 예제

6.18 함수 포인터의 배열

6.19 형 한정자 const와 volatile

생 략.

(41)

이 문서는 나눔글꼴로 작성되었습니다. 설치하기

감사합니다.

참조

관련 문서

실편은 순형으로 부풀어 있으며 섭합상 배열, 구과는 구형으로 차년 또는 당년성숙 4... Chamaecyparis obtusa

 인자로 들어온 콜백 함수를 계속해서 호출하여 배열의 요소들을 왼쪽에서 오른쪽 방향으로 나아가면서 하나의 값으로 줄임. – 콜백 함수: 어떻게 배열의 원소들을

부울 함수의 간소화.

③ 함수 &gt; 프로그래밍 &gt; 숫자형 팔레트에서 곱하기 함수를 블록 다이어그램에 두고 화씨온도 터미널과 반복 터미널을 입력으로 연결하고 이 함수의 춗력을 C_F

 다음은 객체를 생성하고 동적메모리를 객 체에 할당하며 할당된 메모리를 지우는 프

 전화 또는 편지로 묻는 독자들에게 대답하는 칼럼.  Hotline, Action line, Call Quest, Sound

– 예: 함수 spfilt는 예제 2.9의 기하 평균 필터를 imfilter와 MATLAB의 log 함수와 exp 함수를 사용해서 구현. • 이게 가능할 때, 성능은 항상 훨씬 빠르고, 메모리

[r]