본문 바로가기
IT & AI/AI 지식

C 언어 함수, 배열, 포인터 사용법과 예제

by 빛나는해커 2024. 11. 18.

1. 함수

 

함수의 작성과 사용

  • 함수는 반복적으로 사용하는 코드를 묶어놓은 블록이다.
  • C 언어에서 함수는 반환형, 함수 이름, 매개변수로 구성된다.
  • 함수 정의를 통해 프로그램의 특정 기능을 캡슐화하고 코드의 재사용성을 높일 수 있다.
int add(int a, int b) {
    return a + b;
}
  • 위 코드는 int 타입의 값을 반환하는 add라는 함수로, 두 개의 정수를 더한 결과를 반환한다.
  • 정의된 함수는 함수 이름(매개변수) 형식으로 호출한다.
  • 함수가 호출되면 함수의 실행이 시작되며, return 키워드를 통해 결괏값을 반환한다.
int result = add(3, 4);  // result는 7이 됨
  • 함수 정의는 보통 main() 함수 아래에 위치하는데, 이 경우 컴파일러가 이를 미리 알 수 있도록 함수 선언을 먼저 해야 한다.
  • 함수 선언은 함수의 반환형, 이름, 매개변수를 명시한 것으로 끝에 세미콜론(;)을 붙인다.
int add(int a, int b);  // 함수 선언

 

여러 가지 함수 유형

  • 매개변수가 없는 함수는 외부로부터 값을 받지 않고 자체적으로 동작한다.
void greet() {
    printf("Hello, World!\n");
}

greet();  // Hello, World! 출력
  • 반환값이 없는 함수는 void 반환형을 사용하며, 작업을 수행하더라도 반환값을 갖지 않는다.
void print_sum(int a, int b) {
    printf("합계: %d\n", a + b);
}

print_sum(3, 4);  // 합계: 7 출력
  • 매개변수와 반환값이 모두 없는 함수는 데이터를 입력받지도, 결과를 반환하지도 않는다.
void print_message() {
    printf("이것은 매개변수와 반환값이 없는 함수입니다.\n");
}

print_message();
  • 재귀호출 함수는 함수가 자기 자신을 호출하는 형태로, 특정 문제를 더 작은 문제로 나누어 해결할 때 유용하다.
  • 대표적인 예로 팩토리얼 계산이 있다.
int factorial(int n) {
    if (n <= 1) return 1;
    else return n * factorial(n - 1);
}

int result = factorial(5);  // result는 120이 됨
  • 재귀 호출은 코드의 가독성을 높이는 장점이 있지만, 깊은 호출로 인해 스택 오버플로가 발생할 수 있다.
  • 반복문은 재귀보다 메모리 사용량이 적어 성능 면에서 더 효율적이다.

2. 배열

 

배열의 선언과 사용

  • 배열은 동일한 자료형의 데이터 집합을 의미한다.
  • 배열을 선언할 때는 자료형과 배열의 크기를 지정한다.
int numbers[5];  // 5개의 정수 저장 가능
  • 배열은 선언과 동시에 초기화할 수 있다.
int numbers[5] = {1, 2, 3, 4, 5};
  • 배열의 각 요소에 접근할 때는 반복문을 사용하는 것이 일반적이다.
for (int i = 0; i < 5; i++) {
    printf("%d ", numbers[i]);  // 1 2 3 4 5 출력
}
  • sizeof 연산자를 사용하면 배열의 전체 크기와 각 요소의 크기를 구해 배열의 길이를 계산할 수 있다.
int length = sizeof(numbers) / sizeof(numbers[0]);
printf("배열의 길이: %d\n", length);  // 출력: 5

 

문자를 저장하는 배열

  • 문자 배열은 문자열을 저장하는 데 사용되며, 선언 시 초기화할 수 있다.
char greeting[] = "Hello";
  • 문자 배열에 문자열을 대입할 때는 strcpy 함수를 사용해야 한다.
  • 문자열을 직접 대입할 수 없다.
#include <string.h>

char greeting[10];
strcpy(greeting, "Hi");
  • gets() 함수는 문자열을 입력받을 때 사용하며, puts() 함수는 문자열을 출력할 때 사용된다.
char name[20];
gets(name);  // 사용자로부터 문자열 입력
puts(name);  // 입력된 문자열 출력
  • 문자열의 끝에는 항상 널 문자(\0)가 있어야 한다.
  • 만약 널 문자가 없다면 문자열의 끝을 알 수 없으므로, 프로그램이 예기치 않은 동작을 하게 된다.

3. 포인터

 

포인터의 기본 개념

  • 포인터는 변수의 메모리 주소를 저장하는 변수이다.
  • 이를 통해 변수의 위치를 직접 참조하거나 조작할 수 있다.
  • 주소 연산자 &는 변수의 메모리 주소를 구하는 데 사용된다.
int a = 10;
int *p = &a;  // a의 주소를 p에 저장
  • 간접 참조 연산자 *는 포인터가 가리키는 주소의 값을 참조한다.
  • 이를 통해 포인터를 사용해 변수의 값을 간접적으로 접근할 수 있다.
printf("a의 값: %d\n", *p);  // a의 값 출력: 10
  • 포인터는 배열, 함수의 매개변수 등 여러 곳에서 다양하게 활용된다.
  • 배열의 첫 번째 요소의 주소를 포인터에 저장해 배열을 순회할 수 있다.
int numbers[] = {1, 2, 3};
int *p = numbers;
for (int i = 0; i < 3; i++) {
    printf("%d ", *(p + i));  // 1 2 3 출력
}
  • const 키워드를 사용하여 포인터가 가리키는 값을 변경하지 못하도록 할 수 있다.
const int value = 100;
const int *p = &value;
// *p = 200;  // 오류: const로 지정된 값을 변경할 수 없음

 

포인터 완전 정복을 위한 포인터 이해

  • 주소는 메모리에서 변수의 위치를 나타내는 숫자이며, 포인터는 이 주소를 저장하는 변수이다.
  • 포인터의 크기는 운영체제에 따라 달라지며, 보통 32비트 시스템에서는 4바이트, 64비트 시스템에서는 8바이트이다.
  • 포인터 변수에 다른 자료형의 주소를 대입하려면 형변환이 필요하다.
  • 예를 들어 int형 포인터에 float형 변수의 주소를 대입하려면 (int *)와 같은 형변환을 해야 한다.
  • 포인터는 효율적인 메모리 사용, 함수 간의 데이터 공유, 동적 메모리 할당 등을 가능하게 한다.
  • 특히, 배열과 문자열, 함수 인자 등을 다룰 때 매우 유용하다.

C 언어 기본 함수, 배열, 포인터 사용법 소개 이미지