티스토리 뷰

표준 함수 

문자열 함수 

#include <stdio.h> 헤더 파일 추가해야 문자열 함수 사용 가능

1. strcat(String Concatnate) 

  • 문자열끼리 연결하는 함수
  • strcat(dest ,src) : src 문자열을 dest 문자열 뒤에 붙인다. dest + src 
  • strncat(dest, src, maxlen): src의 문자열에서 maxlen의 개수만큼 dest문자열 뒤에 붙임
  • dest 문자열은 해당 함수를 사용하여 문자열이 늘어나면 원본도 변하는 거 같음

2. strcpy(String Copy)

  • 문자열 복사하는 함수
  • strcpy(dest, src)
  • src의 문자열을 dest 문자열에 복사 (덮어쓰기 개념)
  • strncpy(dest, src, maxlen) : src 문자열에서 maxlen 의 개수만큼 dest 문자열에 복사 (앞부터 덮어쓰여짐)

3. strcmp(String Compare)

  • 문자열을 비교하는 함수
  • strcmp(s1, s2): s1과 s2의 대소 비교 
  • strncmp(s1, s2, maxlen): maxlen의 길이만큼만 s1,s2의 대소를 비교
  • 문자열에 대해서 ASCII 코드를 비교하여 s1이 s2보다 크면 1, 같으면 0, s1이 s2보다 작으면 -1을 반환한다. 
  • 대소를 비교하는 방법은 각 문자열의 같은 index끼리 비교했을 때, 끝까지 확인했을 때 같으면 0을 반환한다. 같은 index끼리 비교하다가 다른 문자열이 나온 index를 기준으로 ASCII 코드를 비교하여 대소를 따진다. 

4. strlen(String length)

  • 문자열의 길이를 알려주는 함수
  • strlen(s); :함수 호출하듯 사용함

5. strrev(String Reverse)

  • strrev는 문자열을 거꾸로 뒤집는 함수
  • strrev(str); : str 내에 문자열을 거꾸로 뒤집음 //함수 호출하듯 사용함

6. strchr

  • 문자열 내에 일치하는 문자가 있는지 검사하는 함수
  • strchr(str,c); : str 내에 c가 존재하는 지 알려준다.

수학 함수 

#include <math.h> 헤더 파일 추가

1.sqrt

  • 양의 제곱근을 계산하는 함수이다.
  • sqrt(n); : 루트 n의 값을 계산
  • 관련 자료 확인 바람

2. ceil

  • ceil(n); :소수점 올림

3. floor

  • floor(n); : 소수점 내림

유틸리티 함수

<time.h> & <stdlib.h>

1. rand(Random)

  • rand 는 임의의 값을 생성하는 함수
  • rand(); : 임의의 정숫값 1개 생성, 인자 x
  • 0~ 32767 중에 하나의 값을 반환, 여러번 실행 시 동일 숫자가 나올 수 있음

2. srand(Seed Random)

  • srand 는 난수 생성 알고리즘에 사용하는 seed*를 정해주는 함수(seed란 난수 알고리즘 실행하기 위해쓰는 수이다.)
  • srand를 사용하면 rand 함수를 사용할 때 해당 seed 값에 해당하는 난수 패턴으로 생성한다.
  • srand(seed); : seed 값에 따라 난수 발생기를 초기화한다. 

3. time

  • 현재 시간을 가져오는 함수
  • 1970년 01월 01일 이후로 몇 초가 경과했는지를 나타낸다. 
  • time(NULL); : time함수에 파라미터를 NULL로하면 현재 시간을 리턴한다. 
  • 컴퓨터는 난수를 난수 생성알고리즘에 의해서 만드는데, 난수 생성알고리즘의 seed  값이 같으면 프로그램을 실행할때마다 계속 똑같은 패턴의 난수를 만들게 된다. 그래서 seed 값을 프로그램 시작할 때마다 다르게 하도록 seed에 time함수를 사용한다. e.g.) srand(time(NULL))

4. atoi(ASCII to Integer)

  • 문자열을 정수형으로 변환하는 함수
  • atoi(str); : 문자열 str을 정수(int)로 변환

5. atof(ASCII to Float Point)

  • 문자열을 실수형으로 변환하는 함수
  • atof(str); : 문자열 str을 실수형(float, double)로 변환 

6. itoa(Integer to ASCII)

  • 정수형을 문자열로 변환하는 함수
  • itoa(value, str, radix); :value를 변환하여 str에 radix 진수로 저장한다. 

포인터  ⭐⭐⭐

포인터(pointer)란? 

  • 주소를 저장하는 변수이다. 
  • 기존의 변수는 데이터를 저장하는데 반하여 포인터는 메모리 공간의 주소를 저장한다.
  • 포인터 변수가 주소를 저장하려면 변수의 주소를 알아야 한다. => 변수 이름 앞에 & 연산자를 붙이면 해당 변수의 시작주소를 반환한다.
  • 더 나아가 포인터 변수가 저장하는 변수의 주소에 저장된 값을 참조하려면 * 연산자를 사용한다. 

포인터 변수 선언 및 사용

포인터 변수도 변수이기 때문에 먼저 선언해야 한다. 

  • 자료형* 포인터 변수이름
  • e.g) int형 변수의 주소를 담고 싶다면 `int* 변수이름` 이렇게 포인터 변수를 선언
#include <stdio.h>

int main() {
    int* p = NULL;
    int i = 10;
    p = &i;
    
    printf("변수 i의 주소값 : %p \n", &i); //00CFF9BC
    printf("포인터 p의 값 : %p \n", p); //00CF9BC
    printf("포인터 p이 가리키는 값 : %d \n", *p); // 10
    
    return 0;
}
  • 변수의 크기가 자료형에 따라 달라지는 것처럼 포인터 변수도 자료형에 따라 크기가 달라지기에 여러 가지 포인터 변수가 있는 것으로 착각할 수 있지만 그렇지 않고 모든 포인터 변수의 크기는 같다.=> why? 값이 아니라 `주소`를 저장하기 때문이다. 
  • 32비트 운영체제라면 4바이트, 64비트의 운영체제라면 8바이트로 모든 자료형의 포인터 변수의 크기가 같다.
  • 다만 포인터 연산을 수행할 때 그 주소에 있는 값을 읽어야하는 부분이 생길 수 있어 어떠한 자료형의 주소인지 알려주기 위해 여러가지 변수 타입으로 포인터 변수를 선언하는 것이다. 

  • i 라는 변수를 선언하고 메모리의 특정 주소에 할당이 되면 그 변수의 주소를 가르키는 포인터 변수 p를 선언한다. 
  • i 변수의 주소를 p 포인터 변수에 대입할 때는 & 연산자를 사용하며 그 주소에 있는 값을 가지고 올 때는 *연산자를 사용한다. 

포인터 연산

포인터 또한 변수라서 값을 더하거나 뺼 수 있다. 다만 곱셈이나 나눗셈은 불가능하다. 

포인터 변수에 대한 연산은 일반적인 변수에 대한 연산과 다르다.

포인터에 증가 연산 ++을 적용하였을 경우, 증가되는 값은 포인터와 변수의 자료형 바이트 크기만큼 증가된다.

  • 즉, char형일때는 1씩, short형이면 2씩, int나 float은 4, double형이면 8씩 증가한다. -- 감소연산도 동일

포인터에 정수를 더하거나 뺄 때도 마찬가지이다. 포인터에 정수를 더하면 포인터의 값이 단순히 그만큼 증가하는 것이 아니라 마찬가지로 포인터가 가리키는 자료형의 크기 만큼 증가하게 된다. 

  • 즉, 포인터의 자료형의 크기가 n일 때, 포인터에 정수 m을 더하면 포인터 값은 n*m 만큼 증가한다. 증감 연산자를 포인터에 적용할 수도 있으며 포인터에 가리키는 대상에 적용할 수도 있다. 
  • 포인터 연산 시 주의할 점 연산자 우선순위로 결과값이 다를 수 있다. (*연산자 우선순위: 증/산/시 관/비 논/삼/비)

포인터와 배열의 관계

#include <stdio.h>
int main() {
    int a[] = {10,20,30,40,50}; 
    printf("배열 a[0]의 주소값 = %p \n", a);
    printf("배열 a[1]의 주소값 = %p \n", a + 1);
    printf("배열 a[0]의 값 = %d \n", *a);
    printf("배열 a[1]의 값 = %d \n", *(a + 1));
    return 0;
}
  • 배열 이름을 포인터라고 생각하고 *a를 출력하면 첫번째 요소 a[0]이 출력된다. 또한, a+i는 a가 포인터이므로 배열 시작 주소에 (i*배열 요소의 크기)이 더해진다. 따라서 a+i는 &a[i]와 같고 *(a+i)는 a[i]와 완전히 동일하다. 

call by reference, 포인터 활용 예시

#include <stdio.h>

void swap(int *num1, int *num2) {
    int temp = *num1;
    *num1 = *num2;
    *num2 = temp;
}

int main() {
    int num1 = 10;
    int num2 = 20;

    printf("num1의 값 : %d\n", num1);
    printf("num2의 값 : %d\n", num2);

    swap(&num1, &num2);
    printf("\nSwap함수 실행 후\n\n");
    
    printf("num1의 값 : %d\n", num1);
    printf("num2의 값 : %d\n", num2);
}

=> 결과 값으로 main함수의 지역 변수 num1 과 num2 의 값이 swap되어 num1은 20, num2는 10이된다.

  • 포인터의 장점은 어느 곳에 있든지 주소를 직접적으로 참조함으로써 값을 가져올 수 있고 변경할 수 있다는 점이다.
  • swap함수의 인자로 &num1, &num2로 주소값을 넘겨서 값이 변경될 수 있다. 
  • 만약 주소 값을 넘기는 것이 아니라 그냥 변수의 값을 매개변수로 전달하게 되면 값이 복사되어 함수로 전달된다. 이를 다른 말로 call by value라고 하며 이렇게 되었을 시에는 원본의 num1과 num2의 자리를 바꾼 것이 아니기에 전혀 의미없는 함수의 동작이 되었을 것이다. 

포인터 사용 시 주의점 

1. 포인터 변수 선언 시 초기화하기 

  • 포인터가 선언만 되고 초기화되지 않는다면 포인터는 쓰레기값을 가지게 된다. 이런 상태에서 포인터를 사용하여 메모리의 내용을 변경한다면 문제가 생길 수 있다. 그렇기 때문에 포인터를 단순히 선언만 하는 것이 아니라 선언 시 초기화를 사용하거나 NULL 포인터로 만들어주는 것이 바람직하다.

2. NULL 포인터의 사용

  • 처음부터 포인터가 아무것도 가리키지 않을 때는 NULL로 설정하는 것이 좋다.
  • NULL은 헤더 파일 stdio.h에 0으로 정의되어 있다. => 주소 0은 CPU가 사용하는 영역이어서 일반 프로그램은 주소 0에 접근할 수 없기 때문에 안정성이 높다.

3. 포인터 자료형과 변수의 자료형 일치

  • 만약 포인터의 자료형이 변수의 자료형보다 크다면, 포인터를 통해 변수의 주소를 통해 쓰게 될 경우 변수 범위를 넘어가서 이웃 바이트를 덮어쓰게 되어 문제가 생길수 있으므로 맞춰줘야 한다.

4. 절대 주소 사용 금지

  • 절대 주소는 아두이노와 같은 임베디드 시스템에서만 사용한다. 그 이유는 PC는 윈도우와 같은 운영체제가 프로그램을 관리하기 때문에 프로그래머가 사용하고자 하는 주소가 어떠한 용도로 사용되는 지 모르기 때문이다.
  • 실행을 할 때마다 할당되는 주소가 다르기에 절대 주소는 사용하면 안된다.

포인터 내용 allref: https://coding-factory.tistory.com/636

 

[C언어/C++] 포인터(Pointer) 사용법 & 예제 총정리

포인터란(Pointer)? 포인터는 주소를 저장하는 변수입니다. 기존의 변수는 데이터를 저장하는데 반하여 포인터는 메모리 공간의 주소를 저장합니다. 포인터 변수가 주소를 저장하려면 변수의 주

coding-factory.tistory.com

 

댓글