C 이론(16)

Hi Beck·2023년 6월 11일

TIL-Language(C & C++)

목록 보기
21/34

배열복습

1.C언어에서 배열을 매개변수로 쓸 땐 무조건 사이즈로 쓸 매개변수를 하나더 같이 써줘서 인자를 2개로 받아야된다.

예시로 아래와 같이 함수정의문이 있을때
int average(int score[], int n)
{

}

이유: 원래는 size를 sizeof(배열명)/sizeof(배열명[0])로 구해야되는데 함수를 정의하는 시점에서는 크기를 모르니 일단 임의의 매개변수로 사이즈를 받는 것

2.매개변수,인자 그리고 지역변수의 관계

#include <stdio.h>
#define STUDENTS 5

int get_average(int[], int); //함수 선언문

int main(void) //메인 함수문
{
int grade[STUDENTS] = { 1, 2, 3, 4, 5 }; //배열선언
int avg;

avg = get_average(grade, STUDENTS); //함수 호출문

printf("평균은 %d입니다.\n", avg);

return 0;
}

int get_average(int score[], int n) //함수 정의문
{
int i;
int sum = 0;
for(i = 0; i < n; i++)
sum += score[i];
return sum / n;
}

위와 같은 코드처럼 함수 호출문에서 인자로 지역변수인 임의의 배열(grade)을 쓸 때
함수정의문의 매개변수 int score[]는 임의의배열을 받는 역할을 한다.

근데 이 매개변수는 함수정의문 내에서만 살아있는 지역변수이고,이 변수는 첫번째원소로 배열을 받아와야된다.그래서 인자로 grade 즉 배열의 이름을 받아오는데
'배열의 이름'은 곧 '주소값'과 같다.
주소값을 인자로 넣으면 함수에선 어떻게 받아들이냐면 함수의 이름을 score[]라고 지었지만 grade의 주소값(=우리가 받아온 메모리의 주소값)을 넣었기때문에 함수는 자신이 인자 배열의 메모리(grade)에 가서 읽거나 쓸 수 있겠다라고 인식.(=메모리 접근 가능)

=

보통 함수정의문에 있는 지역변수는 함수 호출 될때만 메모리를 빌려받아올 수 있는데
빌려오지않고 배열의 주소값을 받아온걸로 배열의 메모리를 같이 공유하는것과 같은것

=

ㄱ.

배열 grade의 메모리 공간이 이렇게 생겼다고 가정하면 int형 grade는 사이즈가 5라는 가정하에 20바이트의 메모리 공간을 점유하여 쓴다.

ㄴ.

함수를 정의하는데 score이라는 매개변수(지역변수)를 만들건데 원래 지역 변수를 만들때는 호출할 때 메모리공간을 빌려오는데 이렇게 안하고 배열 grade가 인자로 쓰여 주소값으로 받을시 예외로 이 주소값을 그대로 가져다 공유한다.

ㄷ.

score[ ]가 grade에 빌붙어서 Oxo1(예시의 주소값)을 받아 Ox21까지의 메모리공간을 같이씀

메모리의 원래 이름 즉,메인함수 내에선 grade지만 score라는 별명을 지어준거고 둘은 같은 내용이 된다.다만, 함수정의문내에선 불리는 이름이 score인 것.

=> 이런 사실로 알게 된 것은 주소값은 다른 변수와는 달리 예외적으로 지역변수의 영향을 받지않는다!

ㄹ.
grade[0] = score[0]이 있는데 이게 무슨 의미냐면
score[0]을 3으로 바꾼다면 같은 메모리를 공유하기에 grade[0]에도 3이 들어간 것임.

결론 : 메모리를 공유하고 싶을땐 주소값을 써준다.

3.배열,엔드연산자 그리고 주소값의 관계

배열 -> &(엔드연산자) 불필요
이유 : 배열이름 자체가 주소값이니깐

배열을 쓰지않고 그 외의 변수를 쓰는 경우
-> &(엔드연산자) 필요

  • 변수에 접근할때는 무조건 &를 써주자

배열을 쓰는데 배열명[i]로 쓰는 경우(=배열의 원소에 접근하는 경우)
-> &(엔드연산자) 필요
이유 : 배열 중 원소 하나에 접근하는건 int형 변수 하나에 접근하는 것과 같은 것.

ex)
scanf("%d", &grade[i])

grade[i]가 scanf 함수의 매개변수 자리에 주소값을 인자로 넘겨줘야 scanf 함수에서 grade[i]의 메모리를 공유하는데 그럴려면 인자의 주소값을 함수로 넘겨주는 &를 붙여줘야되는것.(= "여기에 내 값을 입력할거야"랑 같음)

엔드연산자의 역할을 변수의 메모리 공간을 공유해주는 역할을 한다.
그리고 공유받은 함수는 내부에서 반환했을때 그 값이 변환되면 메인함수의 배열 인자도 똑같이 변환된다.

*형식지정자
&와 관계가 없으며,c언어 scanf를 포함한 함수들은 옛날 함수라 입력할 데이터의 자료형을 따로 항상 컴퓨터에게 알려줘야된다.그래서 그걸 표기하기위해 형식지정자를 써주는 것.

*printf
반대로 프린트에프 함수는 값을 변경시키는게 아니라 그저 찍기만 하는거여서 주소값이 필요없다.

4.배열이 함수의 인수인 경우 예시

#include <stdio.h>
#define SIZE 7

void square_array(int a[], int size);
void print_array(int a[], int size);
void square_element(int e);

int main(void)
{
int list[SIZE] = { 1, 2, 3, 4, 5, 6, 7 };

print_array(list, SIZE);
square_array(list, SIZE); // 배열은 원본이 전달된다.
print_array(list, SIZE);

printf("%3d\n", list[6]);
square_element(list[6]); // 배열 요소는 복사본이 전달된다.
printf("%3d\n", list[6]);

return 0;
}

void square_array(int a[], int size)
{
int i;
for(i = 0; i < size; i++)
a[i] = a[i] * a[i];
}

void square_element(int e)
{
e = e * e;
}

void print_array(int a[], int size)
{
int i;
for(i = 0; i < size; i++)
printf("%3d ", a[i]);
printf("\n");
}

  • 각 정의된 함수의 매개변수명이 동일한데 배열로 부터 메모리를 공유하면 문제가 없나?
    -> 이름이 동일해도 독립된 매개변수기때문에 같은 공간을 공유하지만 동일명을 쓰는건 문제가 없다.

위 그림은 코드 내 list 배열 인자와 square_array 및 print_array의 매게변수 a의 관계를 표현한 그림인데 일단 list의 총크기는 4바이트 * 원소 갯수의 7 즉 28바이트다.
할당된 주소값을 예로 들면 Ox01부터 Ox29까지 1부터 7이 들어있는상태다.

코드를 차례로 돌리면

일단 print_array에 list값이 들어가 1, 2, 3, 4, 5, 6, 7 가 그대로 출력된다.

그 다음
square_array가 list를 인자로 받아 코드가 돌아가면 i가 0부터 6까지 돌아가고 for문을 거치면 그림과 같이 1,4,9,16,25,36,49가 된다.(list[6]=7인거 주의)
이때 square_array는 배열의 이름을 받았기에 list배열의 원소의 값들이 변경된다.

그래서 다음
print_array(list, SIZE);에선 1,4,9,16,25,36,49가 출력된다.

이제 인자로 배열 전체가 아닌 6번째 원소를 받기 시작함
printf("%3d\n", list[6]);은 단순 출력문으로 주소값을 받아오는게 아닌 단순 변수값을 가져오는것과 같은데 이때 list는 이전과 다르게 데이터값이 갱신되었으므로 7이 아닌 49가 출력하게된다.

square_element(list[6]);는 e = e e;가 함수 내용인데 중요한건 얘는 애초에 배열을 매개변수로 받아오는 함수가 아닌 변수를 받아오는 함수다.
'49'를 받아와 49
49의 결과값을 가지는건데 여기서는 이 값이 &도 없고 배열의이름도 아니기에 결국은 주소값을 넘겨받은게 아니라 지역변수이기 때문에 함수를 벗어나면 사라지는 데이터일뿐임

profile
Emotional realizer

0개의 댓글