scanf_s는 scanf의 보안에 더 효과적인 방법이다. 사용방법의 차이는 scanf_s는 char 또는 *char를 사용할 때 버퍼크기를 인자로 더 보내야 한다. #include int main(){ char k[10]; scanf_s("%9s", k, 10); printf("%s", k); return 0; } 다음 코드에서는 '\0'을 제외하고 9개의 문자를 받는다. 하지만, 버퍼크기를 주지 않으면, 출력이 되지않는다. 이렇게 한 이유는 buffer overrun이나 buffer overflow같은 것을 이용한 공격을 방어하기 위함이라고 한다.
C언어에서 매크로는 #define지시자를 통해 만들 수 있다. 매크로는 일반함수와는 다르게 프로그램이 컴파일 되기 전에 변경하게 된다. 다음과 같은 코드가 있다. #include #define CAL(x) x*2-1 int main(){ printf("%d\n", CAL(5) ); return 0; } 이 코드를 컴파일하게 되면, 값이 printf("%d\n", x*2-1 ); 으로 변경된다. 하지만, 이 코드에는 문제가 있다. 만약, 다음과 같다면 어떻게 될까? #include #define CAL(x) x*2-1 int main(){ printf("%d\n", CAL(5) * CAL(5)); return 0; } 보통 5*2-1 = 9이므로, 9*9 = 81을 예상하게 된다. 하지만, 매크로는 CAL..
헤더를 추가할때, #include또는 #include "mydef.h"와 같이 쓰게 된다. 어떤 경우에는 꺾쇠괄호를 사용하고 어떤 경우는 큰 따옴표를 사용할까? 꺾쇠괄호는 표준 헤더파일에 사용한다. 꺾쇠를 사용했을때, 컴파일러는 현재 디렉터리에서 파일을 찾지 않고, 표준 헤더 디렉터리에서 찾는다. 그렇기 때문에 지역 헤더 파일로 프로그램을 컴파일하기 위해서는 큰 따옴표를 사용해서 표기해야한다. 관련 예시> #include #include"mydef.h" int main(){ const char* value = printMydef(); printf("%s\n", value); return 0; } mydef.h #pragma once; const char* printMydef(); mydef.c #incl..
함수포인터는 함수를 가르키는 포인터이다. 함수포인터 배열은 여러 함수들을 나타내게 할 수 있고, 배열을 이용해 일반 변수 값에 접근하는 것과 같은 방식으로 배열처럼 함수들에게 접근 할 수 있다. void displayA(void){ printf("Call A\n"); } void displayB(void){ printf("Call B\n"); } int main(){ int i=0; void (* display[]) (void) = { displayA, displayB }; for(i=0; i
함수포인터는 단순 포인터 변수가 변수의 주소값을 가르키듯이, 함수 포인터는 함수의 주소를 저장한다. 실제 함수 명이 아닌, 다른 이름으로 참조할 수 있다. void displayA(void){ printf("Call A\n"); } int main(){ void (* display) (void); display = displayA; display(); return 0; } 다음과 같은 코드에서 display가 displayA를 가르키기 때문에, display()만을 호출했을 때, 참조되어지는 displayA가 호출된다.
포인터에 붙는 Const의 위치에 따라 모두 다른 의미를 가지게 된다.Const int *변수명데이터를 상수화하며, 포인터는 조작할 수 있다.int * const 변수명포인터를 상수화하며, 데이터는 조작할 수 있다.const int * const 변수명데이터와 포인터를 모두 상수화시켜서, 아무것도 변경할 수 없다.int const *변수명데이터를 상수화하며, 포인터는 조작 할 수 있다. 주석처리 된 부분은 모두 사용될 수 없다. int main(){ int tmp = 100; const int *ptr1 = &tmp; int * const ptr2= &tmp; const int * const ptr3= &tmp; int const *ptr4 = &tmp; //++(*ptr1); //++ptr2; //++..
int main(){ char *pt = "apple"; printf("%s \n", pt); return 0; } 다음과 같은 코드가 있다. pt값은 변경이 될 수 없다. 이유는 "apple"이라는 문자열은 문자열 상수로 상수가 저장되는 영역에 저장되게 된다. 그 저장된 "apple"이라는 문자열 상수에 pointer가 주소를 가르키는 꼴이 되고 만다. 상수는 바꿀 수 없기 때문에 상수 값 변경한다면 문제가 생길 수 있고, const char *pt = "apple";로 선언하는 것이 좀 더 좋은 방법인것 같다. 문자열 수정을 하기 위해서는 어떻게 할까? 문자열 수정을 위해서는 배열을 사용해도 된다. 배열은 상수영역에 있는 "apple"을 가져와 복사를 하여 스택 영역에 둔다. 때문에 변경을 해도 아무..
아래와 같은 소스가 있다. int main(){ char arr[5]; scanf("%s", arr); printf("%s %d\n", arr, sizeof(arr)); return 0; } scanf()를 사용한 이 소스를 실행시켜 보면, '\0'을 제외하고 4자를 입력할 수 있다. 하지만, 사용자가 5자 이상을 입력했을 때, 프로그램이 크래시 되고만다. 반면, fgets()는 문자열의 최대 크기를 지정한다. int main(){ char arr[5]; fgets(arr, sizeof(arr), stdin); printf("%s %d\n", arr, sizeof(arr)); return 0; } 그렇기 때문에 아무리 많은 글의 문자열을 입력하더라도 에러를 막을 수 있다. 이를 위해서 scanf()를 가..
이 이유를 알기 위해서는 다음과 같은 소스를 실행해 볼 필요가 있다. int main(){ int arr[] = { 2, 4, 6, 8 }; printf("index = 0 > %d, ", arr[0]); printf("%d\n", *arr); printf("index = 2 > %d, ", arr[2]); printf("%d\n", *(arr + 2)); return 0; } 배열 변수는 첫 번째 항목에 대한 포인터로 사용할 수 있다. 그렇기 때문에 arr[2]는 *(arr + 2)로 표현이 된다. 즉, 첫번째 배열주소에서 int(4byte)만큼의 주소번지를 이동하여, 다음 값을 읽는다. 결론 : arr의 경우 첫 주소는 아무 값도 더하지 않는 0부터 시작하게 된다.
- Total
- Today
- Yesterday