본문 바로가기
타입스크립트로 함께하는 웹 풀 사이클 개발(React, Node.js)/TIL

데브코스 11주차 Day 3 - 변수와 메모리 생명주기, 배열과 포인터 with C

by 슈크림 붕어빵 2024. 1. 27.

함수

 

함수의 기본 형태 - c

  • 자료형 - 함수가 리턴하는 값의 타입
  • 함수 이름 - 함수의 기능과 밀접한 것으로 만드는 것이 좋음
  • 인수 목록 - 함수에 필요한 값을 전달할 때 사용
  • 함수의 내용 - 중괄호 {} 사이의 영역 안에서 작성
    자료형 함수이름 (인수 목록){
        함수의 내용
    }

 

함수의 호출과 흐름

  • main 함수에서 차례로 내려감
  • 함수가 호출되면 해당 함수의 주소로 점프
  • return이 되면 호출했던 지점으로 돌아감.
  • 다시 내려감

 

void 타입

  • 결과값을 리턴하지 않는 함수
  • #include <stdio.h>
    
    void printArea (int w, int h){
        printf("넚이: %d",w*h);
    }
    
    int main() {
        int w,h;
        scanf("%d %d",&w,&h);
        printArea(w,h);
        return 0;
    }

변수의 범위

- 지역변수

  • stack 메모리에 쌓이게 된다. (FILO)
  • stack 메모리에서 소멸되는 순간: 함수가 종료되는 순간
  • 함수 호출 순서와 소멸 순서는 반대
    • 아래를 참고

전역변수

  • 함수 바깥쪽에 선언된 변수. 어디서든 사용할 수 있다.
  • 프로그램이 시작하자마자 메모리상에 올라가서 프로그램이 종료될 때 메모리상에서 소멸된다.
  • 메모리 공간중 스택, 힙, 데이터영역 중 데이터 영역에 저장됨

Static 변수

  • 사전적 의미로 '정지된', '고정상태의' 뜻을 갖는다.
  • 지역변수처럼 중괄호 영역에서 선언되지만, 중괄호를 벗어나도 메모리상에 고정되어 소멸하지 않는다. 즉, 프로그램이 종료될 때 소멸
  • 아래와 같은 경우 func가 두번째 호출이 되어도 처음 선언되었던 value가 소멸되지 않았기 때문에 그대로 더해진다.
#include <stdio.h>

void func(){
    static int value =0;
    value++;
    printf("%d ",value);
}

int main() {
    for (int i=0;i<5;i++){
        func();
    } 
    return 0;
}

=> 출력 : 1 2 3 4 5

 

문자열 배열과 null

 

문자열 변수

맨 뒤는 null 문자가 붙어야한다.

 

null문자가 왜 필요할까?

char str[100] = "hello world";
  • 문자수는 11개지만 배열의 크기는 100이므로 81개가 남는다.
  • 남은 공간에는 쓰레기값으로 채워져 있다.
  • 컴퓨터는 어디까지가 필요한 값인지 알 수 없기 때문에 null로 구분한다.

 

포인터

  • 포인터는 포인터 변수의 줄임말로 메모리의 주소값을 저장하고 있는 변수이다. 
  • 보통 주소값을 저장한다는 표현을 반대로 해당 메모리를 가리킨다고도 표현한다.
  • *을 붙여 주소값만 저장하는 포인터 변수를 선언한다. 출력시 %p
#include <stdio.h>

int main() {
    
    int b=10;
    int *pb = &b;

    printf("%d\n",*pb);
    printf("%d\n",b);
    printf("%p\n",pb);
    printf("%p\n",&b);
    return 0;
}

=> 결과

10
10
0x7ffe45c5824c
0x7ffe45c5824c

 

배열 이름의 의미

  • 배열의 이름은 해당 배열의 첫번째 요소의 주소값을 갖는다. 즉, 첫번째 요소의 주소값을 가리키는 포인터라는 의미
  • arr은 &arr[0]의 값과 일치한다.
#include <stdio.h>

int main() {
    int arr[5] = {1,2,3,4,5};
    
    printf("%d\n",arr[0]);
    printf("%d\n",*arr);
    
    printf("%p\n",&arr[0]);
    printf("%p\n",arr);
    
    return 0;
}

=> 결과 : arr[0] == *arr / &arr[0] == arr

1
1
0x7ffd3eeef640
0x7ffd3eeef640

 

배열의 이름 == 포인터? 다른 점

 

배열의 이름이 포인터지만 일반 포인터와 결정적인 차이점이 있다. 

배열의 이름은 포인터 상수이기 때문에 주소값을 변경할 수 없다.

 

배열의 복사

int arr1[5] = {1,2,3,4,5};
int arr2[5];
arr2=arr1;

=> 에러 : 배열의 이름은 상수이기 때문에 대입 연산자를 통해 값을 넘겨받을 수 없다.

 

함수와 포인터

  • 참조에 의한 복사
#include <stdio.h>
void printArr(int *arr){
    for (int i =0;i<5;i++){
        printf("%d ",*(arr+i));
    }
}

int main() {
    int arr[5] = {1,2,3,4,5};    
    printArr(arr);  
    return 0;
}

=> 배열의 주소

 

  • 값에 의한 복사