경일게임아카데미 멀티 디바이스 메타버스 플랫폼 개발자 양성과정 20220429 2022/04/04~2022/12/13

Jinho Lee·2022년 4월 29일
0

경일 메타버스 20220429 4주차 5일 수업내용. C언어 문자열 함수 + 포인터 간략한 설명, 함수

C언어 프로그래밍

https://docs.google.com/document/d/1pTQ2cg7jq36qksTc5IRbD86jXhDA6vpIgkhbzS9uyrk/edit

상수의 사용에서 주의 사항

  • 매직 넘버 : 코드 내에서 어떤 의미인지, 왜 사용했는지 알 수 없는 상수. 지양해야 할 요소.
  • 항상 상수를 쓸 때는 의미를 부여할 것.
  • 기호 상수 : 상수에 의미와 이름을 부여한 것.

C언어 문자열 함수 추가

  • toupper 함수 : 헤더파일 <ctype.h>, 소문자를 대문자로 바꿔주는 함수.

  • strcpy 함수 : 헤더파일 <string.h>, strcpy(문자열 객체 포인터, “문자열” or 다른 문자열 객체 포인터), 문자열 객체에 문자열을 복사해 내용을 바꿔주는 함수.

    • null(’\0’) 종료가 되는 문자열만 받을 수 있다. 안된다면 다른 메모리에 침범. Undefined Behavior

    • Undefined Behavior : 표준에서 정의하지 않은 행동. 어떤 일이 일어날지 예상이 어려움. 프로그래머는 주의해야 함.

  • strcat 함수 : 헤더파일 <string.h>, strcat(문자열 객체 포인터, “문자열” or 다른 문자열 객체 포인터),
    문자열 객체에 문자열을 뒤에 복사해 붙여주는 함수.

  • strlen 함수 : 헤더파일 <string.h>, strlen(문자열 객체 포인터), null문자를 제외하고, 문자열의 길이를 구해주는 함수.

  • typedef 기존타입 새타입 : 타입에 의미를 부여하고 이름을 정의한다.

  • strcmp 함수 : 헤더파일 <string.h>, strcmp(문자열 객체 포인터, “문자열” or 다른 문자열 객체 포인터), 두 문자열을 비교하여 아스키 코드와 길이 순으로 비교하여 상태를 리턴.

  • https://en.cppreference.com/w/c/string/byte

포인터 Pointer

  • 데이터를 메모리 주소값으로 해석. 메모리 주소를 값으로 갖는 객체.

  • 포인터 초기화

  • NULL을 넣거나

  • 다른 객체의 주소를 넣거나

Type Identifier
int
p; ⇒ pointer to int

Member access operators 역참조 연산자

  • [] : array subscript
  • & : address of, 주소 출력. 메모리 주소를 불러온다.
    • : pointer dereference, 간접 참조. 해당 메모리 주소에 있는 값을 불러온다.

왜 포인터를 사용해야 하는가?

메모리에 접근하는 방법은 2가지

  • 직접 참조(Direct Reference / Direct Access) : 메모리 주소에 직접 접근하는 것
    num = 20;

  • 간접 참조(Indirect Reference / Indirect Access) : 메모리 주소를 포인터를 통해서 접근
    *p = 20;

  • Scope (범위) : 프로그램이 식별자를 찾을 수 있는 영역

    • Block Scope : 복합 구문 내 ⇒ Local Variable
    • File Scope : 파일 전체 ⇒ Global Variable
      ⇒ 범위로 인한 메모리에 대한 접근 제한을 피하기 위해 포인터 사용
  • 주의 : C 언어는 안전하지 못한 언어 ⇒ 포인터의 사용에서 형식을 맞지 않게 넣지 않도록 조심할 것.

  • 포인터는 중복 사용(적용) 가능

  • Potinter Type 크기는 얼마인가?

    • Pointer Type : 데이터를 메모리 주소값으로 해석한다.
    • x86 : 4byte
    • x64 : 8byte
  • Address Operation : 주소 연산

    • + - : 메모리 주소를 가리키고 있는 타입의 크기만큼 옮긴다.
    • ++ / -- : 포인터에 대하여 증감연산자도 작동
    • *, / 는 안된다.
  • 배열 : a[b] ⇒ *(a + b);

  • 주의 : 역참조 연산자와 증감 연산자를 결합할 때 연산 순서를 유의해야 한다.

    • *p++; // *p : 역참조를 한 후 p++ : 포인터의 주소값을 증가시킨다.
    • *++p; // ++p : 포인터의 주소값을 증가시킨 후 *p : 역참조한다.
    • ++(*p); // (*p) : 역참조를 한 후 ++p : 역참조한 값을 증가시킨다.
    • 위의 세 개는 의미가 많이 다르다 - 우선순위 때문.
    • 우선순위 ++ > *
  • void* p; // pointer to void(int, double, fuction, ~)

  • Deference X : 내가 가리키고 있는 타입이 뭔지도 모르는데 어떻게 해석?

  • Address Operation? : 가리키는 타입이 없기에 사용 불가

  • 다만 어떤 주소든 담을 수 있기에, 주소 자체만을 사용할 때 유용하다.

예시

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

void Swap(int* a, int* b)
{
   // a : 0x1234 -> 0xabcd
   // b : 0x5678 -> 0x5780
   int temp = *a;
   *a = *b;
   *b = temp;
}

int main(void)
{
   char input[] = "A bird came down the walk";
   
   // Pointer : 데이터를 메모리 주소값으로 해석
   // Type* Identifier;
   // int* p; => pointer to int

   int a = 10; // a : 0x1234
   int b = 20; // b : 0x5678

   // a <-> b
   Swap(&a, &b);
   printf("%d %d", a, b);

   int num = 10;
   int* p2 = NULL;
   int* p = &num;

   int* * p3 = &p; // pointer to pointer to int
   **p3 = 30;

   int*** p4 = &p3; // pointer to pointer to pointer to int
   ***p4 = 50;

   

   *p = 20;

   // 왜? 포인터를 사용해야 하는가
   // 메모리에 접근하는 방법은 2가지가 있다.
   // 직접 참조(Direct Reference / Direct Access) : 메모리 주소에 직접 접근하는 것
   // num = 20;
   // 간접 참조(Indirect Reference / Indirect Access) : 메모리 주소를 포인터를 통해서 접근하는 것
   // *p = 20;
   a;
   // Scope : 프로그램이 식별자를 찾을 수 있는 영역
   // Block Scope => Local Variable
   // File Scope => Global Variable
   
   // Pointer Type 크기는 얼마인가?
   // Pointer Type : 데이터를 메모리 주소값으로 해석한다.
   // x86 : 4byte
   // x64 : 8byte


   // + - : 메모리 주소를 가리키고 있는 타입의 크기만큼 옮긴다.
   // ++ / --
   // Address Operation : 주소 연산
   int arr[2] = { 10, 20 };
   p = arr; // arr의 첫 번째 원소의 주소를 가리키게 된다.
   p = p + 1; // &arr[1]
   p = p - 1; // &arr[0]
   ++p;
   --p;
   p++;
   p--;

   char* pch; // pointer to character
   pch + 1; // 1 바이트만큼 뒤로
   pch - 1; // 1 바이트만큼 앞으로

   // a[b] => *(a + b);
   p = arr;

   // 주의 : 역참조 연산자와 증감 연산자를 결합할 때 연산 순서를 유의해야 한다.
   int num2 = *p++;
   num2 = *++p;
   num2 = ++(*p);


   printf("\n%d", sizeof p);
   
   // [1][2][3]
    //        p

    int n = *p++; // n = 1
    // *p : 역참조를 한 후
    // p++ : 포인터의 주소값을 증가시킨다.

    int n = *++p; // n = 3
    // ++p : 포인터의 주소값을 증가시킨 후
    // *p : 역참조한다.

    int n = ++(*p); // n = 4
    // *p : 역참조한 후  3
    // ++ : 역참조한 값을 증가시킨다.

함수

  • Fuction, Procedure
  • 함수는 복합 구문에 식별자를 붙인 C 언어 구성 요소다. 즉, 일련의 과정에 이름을 붙인 것이라고 할 수 있다. 함수는 헤더(Header)몸체(Body)로 나뉜다.
  • 문법 : https://en.cppreference.com/w/c/language/functions
  • 선언
    • return-type identifier(parameter-list) ⇒ Header
    • complicated statement ⇒ Body
  • 함수는 0개 이상의 매개변수(Parameter)를 가질 수 있으며, 매개변수는 함수의 몸체에서 활용될 수 있는 변수다. 매개변수는 호출 연산자를 사용할 때 인자(Argument)에 의해 초기화 된다. 또 return 구문을 사용해 호출자에게 결과값을 반환할 수 있다. 함수 안에서 함수를 정의할 순 없으며(단, 선언은 가능하다.), 그렇기에 함수는 파일 범위를 가진다.
  • 매개변수 Parameter
    함수에서 사용되는 변수.
  • 함수를 사용한다는 것은 코드를 재사용하기 위함이다.
  • 함수를 호출한다. 호출한 사람을 호출자(Caller), 호출된 함수를 피호출자(Callee)
    • 함수명(매개변수명) : Call Operator
    • 인자(Argument) : 매개변수의 초기값
  • 호출자에게 내가 계산한 결과를 반환해줄 수 있다.
  • 반환은 return문을 사용함. 반환 값은 반환 타입과 일치해야 함.
  • 반환해줄 것이 없다면 void 타입을 사용.
    • 반환 타입이 void인 경우에도 return문을 사용할 수 있으며 함수를 중간에 끝낼 때 사용한다.

예시

int sum(int x, int y)
{
    return x + y;
}

void foo()
{
    if (1)
    {
        // 반환 타입이 void인 경우에도 return문을 사용할 수 있으며
        // 함수를 중간에 끝낼 때 사용한다.
        return;
    }
}

  • 함수가 배열을 받으려면 포인터를 사용해야 한다.
  • 배열을 매개변수로 받는 함수는 배열의 크기를 같이 받는다.
  • 문자열의 끝은 널 문자(Null Character)다. ⇒ 따라서 배열의 크기를 알지 않아도 끝을 알 수 있다.
  • 매개변수 1개 ⇒ 문자열을 저장하기 위한 객체 ⇒ pointer to char
    • strlen() → 어떻게 문자열의 길이를 구할 수 있을까?
      1. str은 문자열이다.
      2. 문자열의 끝은 NULL 문자이다.
    • strchr() → 문자열에서 특정 문자의 최초 위치를 찾는 것
      1. 문자가 있는 경우 ⇒ 그 문자의 위치
      2. 문자가 없는 경우 ⇒ NULL
    • strrchr() → 문자열에서 특정 문자의 마지막 위치를 찾는 것
    • 더미 텍스트 : Lorem Ipsum

예시

// strchr() : 문자열에서 특정 문자의 위치를 찾는 것
// 입력 : 문자열(const char*), 내가 찾을 문자(const char)
// 처리 : 입력된 문자열에서 그 문자가 나온 위치(메모리 주소)를 찾는다.
// 출력 : 문자의 위치 => 그 문자가 있는 메모리 주소값(char*)
// 1. 문자가 있는 경우 => 그 문자의 위치
// 2. 문자가 없는 경우 => NULL
// char* pos = strchr("Hello, 'l');
// "Hello"
//    ↑

// 1. 문제 정의 => 입력, 처리, 출력. 문제를 충분히 해결할 수 있을 정도로 계속해서 작은 단위로 쪼개서 생각해야 함.
// 2. 작은 문제로 쪼갰다면 그 문제를 해결할 절차를 기술.
// 3. 문제를 해결하기 위해 어떤 데이터가 필요한가? => 즉, 어떤 데이터를 저장해야 하는가?

char* strchr(const char* str, const char ch)
{
   while (*str != '\0')
   {
      if (*str == ch)
      {
         return (char*)str;
      }

      ++str;
   }

   return NULL;
}```

0개의 댓글