C 이론(15)

Hi Beck·2023년 5월 31일

TIL-Language(C & C++)

목록 보기
19/34

과외 복습

1.sizeof로 배열전체크기에서 자료형하나로 나누면 배열크기가 나온다.이를 반대로 생각하면 나오는게 "배열의크기 = 자료형크기 * 원소의갯수"

2.배열의 주소값 접근법
첫번째 원소의 주소 -> 배열의이름 = 첫번째원소의 주소값
그외의 원소들의 주소 접근법 -> 첫번째 원소 주소값 + (자료형크기 * 원소의갯수)

3.배열원소 역순 출력
-> for문의 n을 역순으로 출력한다

예시
for(i=SIZE-1;i>=0;i--)
{
}

포인트
ㄱ. 초기화를 -1한 값부터 시작하기
ㄴ. 반복 되면서 음수가 되면 탈출
ㄷ. 증감식은 --로

4.배열을 이용한 최소값 구하기
min=grade[0]을 써줘야되는데 이걸 써주는 이유는 다른값과 비교해서 최소값을 도출하기 위한 기준값으로 쓰기위해서인데 안써주면 min이 0으로 초기화되면서 로직상 최소값을 비교할 수 있는 기준이 안됨(어느수보다 0이 더 작으니깐)

5.배열과함수
int get_average;

int main()
{
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;
}

위와 같이 평균을 구하는 프로그램이 있다고 가정할때 배열을 함수에다가 넘겨주고싶을때는 이렇게 쓴다.(=함수에다가 넘겨준다는 표현은 즉 매게변수로 쓴다는걸 의미함)
우리가 메인에서 scanf처럼 쓰던 변수를 함수로 넘겨주는 경우가 있는데(함수 내 변수는 지역변수로 함수 안에서만 사니깐 변수 자체가 넘어가는게 아니라 그 안의 값이 넘어가는걸 명심)

근데 배열에서 이 개념을 깨는 경우가 나온다.

맨 밑 함수를 정의할때 함수의 매게변수로 배열을 쓸 때는 (int grade[ ], int n) 이런식으로 대괄호를 이용하고 변수 2개를 써준다.

이렇게 쓰는 이유는?
내가 배열을 넘기고싶을때는 매게변수에 위와 같이 껍대기를 만들어줘야된다.
일단 대괄호안 인덱스가 없는 이유는 함수를 호출하기전까진 함수를 정의할 땐 크기를 우리가 얼마나 넣어야될지 모르니깐 일단 배열크기를 대괄호로 두는것

이 배열의 크기를 알 수 있는 방법은 get average를 호출할때 메인 함수안의 인자값으로 주어지는 배열의 크기랑 똑같다는걸 이용해야됨.여러 호출문에서 인자로 받는 배열들은 다양한 인자를 받을것이다.(10개... 5개... 등등) 그렇기에 이 함수는 배열의크기에 상관없이 잘 동작해야된다.(예로 들어 인자가 5면 함수에서도 매게변수는 5가 되는것)

ex)
int grade[STUDENTS] = { 1,2,3,4,5 }; 위에선 지금 STUDENTS라는 크기를 인덱스로 넣어주고 배열의 크기만큼 초기화를 했다.그럼 밑에 매게변수자리에는 int grade[5]가 들어가는거임. 만약 내가 get_average를 또 호출하고싶으면 인자로 다른 크기인 10짜리 뭔가를(STUDENTS말고 다른거,즉 원소의 개수) 넣으면 그때 함수에선 int grade[ooooo]가 되는 것이다.(5개짜리 배열이 될수도 10개짜리 배열이 될수도)

결론은 get_average처럼 함수를 호출할 때 들어가는 인자값 grade, 즉 재료로 쓰이는 배열의값(=grade)이 배열의 사이즈에 따라서 매게변수의 크기가 정해진다.모든 배열을 커버하기위해서 매게변수의 배열을 쓸땐 공백 대괄호로 쓴다.

6.int n은 왜 있나?
호출할때 배열의 크기가 다를때마다 함수를 정의할 수 없으니 이렇게 쓰는건데 이 방식의 문제점은 배열의크기는 인자값으로 받는다 쳐도 함수를 정의할때의 시점에선
int get_average(int score[], int n)의 int score[]의 크기를 모른다.이걸 모르면 함수를 작동시킬때 몸체에서 어디까지 반복으로 돌려야되고 수식에 들어가는 요소를 뭘로 써줘야되는지를 모르니깐 임의적으로 n이라는 변수를 써주고 호출에서 얘도 넘겨받자는 식임. 그래서 매게변수 하나를 더 받는데 그게 원소의개수를 받는 int n이다.
(=함수가 n 범위 안쪽으로 작동하게끔한다)

7.포인터와 어느정도 연관된 변수 심화 문법(배열이 함수의 인수인 경우)

배열을 매게변수로 받는 함수의 경우 매게변수가 바뀌면 이 함수의 호출문의 대응하는 인자(인자가 보통 배열 이름,예시에선 grade)도 영향을 똑같이 받는다.(함수에서 for문이 돌아가서 값이 바뀔때마다 메인의 호출문 인자도 사라지지않고 계속 바뀐다는 뜻.score가 바뀌면 grade도 바뀐다.)

비슷한 경우로 scanf 쓸때 우리가 입력값을 넣으면 &변수에 넣어주고 그값이 지역변수처럼 사라지는게 아니라 그대로 유지가 됨.즉 다른 함수에서 받아온 변수의 값을 바꿀 수 있음.

결론부터 말하자면 매게변수로 배열을 쓰는 경우는 일반 변수와 다르게 지역변수의 범위성 제약을 받지 않는다.

8.이런 이유는?
함수정의문이 따로 있는데 메인에서 scanf에 다른 변수값을 넣으면 기존의 scanf의 변수값도 같이 바뀐다.즉 기존의 값을 우리가 입력한값으로 바꿔버린다.scanf에 썼던 &가 그 이유인데 이 원리는 다음과 같은데 메모리에 접근하는법은 두가지 1.이름으로 접근하는법 2.주소값으로 직접 접근하는법이다.우리가 값을 바꾸고싶으면 직접 메모리에 찾아가서 바꾸는 방법이 확실하기에 후자의 방법으로 선택한다.그러기위해서 쓰는 방법이 엔드연산자를 써주는 방법이고 이걸 쓰면 인자로 나의 주소값을 넘겨준다는것이다.이게 내 것좀 바꿔달라고 주소값을 넘겨줬다는건데(이때 전제는 단순 변수가 아닌 배열형 변수다.)

근데 보통은 지역변수의 성격이면 각 함수 안에 있는 변수는 변경이 되어도 그 함수를 벗어나면 효력이 없어 다른 변수에 영향을 끼치지않는데(함수의매게변수도 지역변수)이건 왜 효력이 있냐는게 논점인데 지금 배열을 매게변수로 쓰면

우리가 배열 선언할때 이름 속 있는 주소값이 있으면 거기에 내 주소를 넘겨준건데
scanf("%d",&grade[i]);면 내 주소를 grade에 넘긴거고 i만큼의 원소 하나하나에 값을 넘겨준다.

정리해보자면 아래와 같다.

=변수의 값을 바꿔줄려고 내가 바꿀 메모리에 접근을 하는건데 나의 주소값이라는건 내가 입력한 데이터의 주소를 의미하고 그걸 변수의 주소에 덮어씌운다는것이고 거기에 남는건 내가 입력한 데이터와 데이터의 주소니깐 다시 호출하지않는이상 코드의 변수의 현재값은 다 내가 입력한 값임.

애초에 선언하고 초기화한 변수는 주소값이 있을건데 그 주소값을 내 주소값으로 바꾸는걸 &를 통해 요청한것이다.
(=내 주소값줄태니깐 형식지정자에 입력한 값으로 바꿔봐)

매게변수가 배열인 경우 호출문에서 배열의 각각 원소에 입력값이 들어간다.(참고로 모든 원소는 &를 붙히면 주소값이 나오기에 배열 중간의 원소도 계산해서 접근이 가능함.이름은 곧 첫주소값 + 자료형크기 )

이렇게 주소값을 받아오는 변수가 포인트변수라고하고,함수에서 외부로부터 주소값을 받아오고싶을때 쓴다.우리가 함수호출의 인자로 배열의 이름을 써주는데 그말은 곧 인자로 배열의 주소값을 준 것
근데 얘는 왜 지역변수의 영향을 안받냐? 포인트변수는 영향 안받는다.

우리가 기존에 알앗던건 변수를 넘길땐 이름이 아닌 값만 복사된다.함수의 형태가 그럴수밖에 없었다 무슨 형태냐면

int 식별자(int n )
{
}

함수 정의문 속 int n 매게변수도 지역변수니깐
이 함수를 메인에서 호출할때 들어가는 변수형태의 인자가 함수로 들어갈때는 값만 들어간다.호출문에서 넘겨준 변수 인자를 가지고 함수에서 돌리는데 거기에 변수값이 달라져도 서로 함수엔 영향이 없음.바꾸고싶으면 이름으로 접근하는게 아니라 주소값으로 접근해야되는것 근데 우리가 쳤던 단순 변수는 이름으로 접근하기에 메모리가 안바뀌는거임

9.배열이 함수의 인수인 경우
피피티 24p
보통 배열을 매게변수로 받는 함수 호출문은 인자가 배열이름하나 인덱스를 뜻하는 하나가 국룰

임의의 함수 호출문 인자에 배열이름을 보면 떠올려야되는건 이름이 뜻하는건 곧 배열의주소니 지금 함수의 매게변수로 주소값이 넘어가는구나가 보여야된다.
넘어간 후 함수 정의문에선 for문이 원소의갯수만큼 돌아갈것이고 반복 내용이 실행될 것임.근데 아까말한것처럼 주소값을 함수에 넘겨주면 거기서 나온 반환값들이 메인함수에서 선언한 list 배열의 값들에 영향을 주고 그 인자로 썼던 배열들의 값이 첨에 선언했음에도 불구하고 바뀐다는것이다. -> 이말은 인자로 배열을 쓰는 호출을 계속하면 배열의 값이 호출 순서에 따라 바뀐다는 뜻이다. -> 결국은 주소값을 넘겨줬기에 이게 가능한거다.
(c언어는 그냥 값을 넘겨주면 그냥 복사만 하고 주소값을 넘겨주면 그 메모리를 그대로 가져다쓰라고해서 가져온다.)

예시 설명 - 지금 여기서 선언한 배열의 주소값을 넘겨줫고 각 함수를 그 배열을 인자로 넣어 호출하여 넘겨준 함수 정의문에서 "나는 int a[ ]를 만들긴할건데 내가 선언하고 초기화한 배열의 주소값에다가 만들라는거구나라는걸 알아야됨.
(=a가 배열이랑 똑같은 주소 즉 똑같은 메모리를 쓰는것)

int a[ ]를 이름보단 별명으로 생각하면 조금 더 나음
어이 형씨라고 부르는 느낌이고
인자로 쓰이는 배열은 곧 a의 진짜 이름이여서 ㅇㅇ야라고 부를 수 있는 느낌
별명이든 실제이름으로 부르든 둘다 영향을 받아 함수 선언 정의 호출문을 보고 그 함수의 변수가 배열이름 즉 주소가 아닌 단순 변수 접근하는거면 그건 지역변수니 배열에 영향을 주지않는다.근데 그 안에 들어가는 배열의 원소들의 값은 영향받은 값들이 들어감

7.포인터
포인터 num의주소값을 ptr에 넣어준다 값이 아니라
Num에접근하는방법은2개 num이름 아니면 oxo1주소에 접근
근데 ptr은 0x01을 가지고있음 이건 즉
Ptr이 num을 가리키고있다는것
Ptr가지고 num을 찾아갈 수 있다
포인터변수는 값보다는 다른변수를 가리킨다는 목적만으로 존재하는애임
포인터변수자체론 가지고있는 가치가없는거임
포인터 ptr가지고 num의값을 변경시키는게 가능해서 그 용도로쓰임
함수호출에서 인자넘겨받을때 쓰인다
변수는 반드시 값을가진다
인트 넘은 인트형 값을가진다
인트별은 인트별형 값을 가진다
그 안에 값으로 뭘가질지는 자료형이 정한다
인트별 = int = 인트포인터형이라고함
을 포인터라고한다
인트별 변수는 인트포인트형태의값을가진다

profile
Emotional realizer

0개의 댓글