[C] NULL과 널문자

NULL은 아스키코드에서 0을 의미(symbol은 NUL)하고 널문자는 '\0'이다. 문자열의 끝을 알리는건 널문자('\0')이지 NULL이 아니다. NULL은 '\0'이 아니다. 하지만 NULL도 0이고 널문자('\n')도 0이다... NULL을 10진수로 표현하면 0이고 널문자도 10진수로 표현하면 0이다. 그렇다면 NULL과 널문자의 차이점은...? NULL은 상수 0을 define 해놓은 것으로 그대로 사용하면 int형 또는 void*형, 즉 4바이트의 자료형이 되지만 널문자는 char형, 즉 1바이트의 자료형이다. (맞나?) 그리고 이러한 차이 때문에 구분되어 사용되어 진다. NULL은 주로 포인터 변수를 초기화 시킬 때... 널문자는 문자열의 끝을 알릴 때... 그래서 NULL과 널문자('\n')는 같지만 다르다. 다음은 Visual Studio 2012의 stdio.h 파일에 정의되어 있는 NULL의 정의이다. /* Define NULL pointer value */ #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NULL ((void *)0) #endif #endif 보는바와 같이 C에서 NULL의 정확한 정의는 (void *)0 이다. NULL == (void *)0 널문자 == '\0' == ((char)0)

[C] 메모리 공간의 할당과 초기화가 동시에 일어나는 상황

출처 - 열혈 C++ 프로그래밍 #include <stdio.h> int SimpleFunc(int num); int main() { int num = 10; // 여기 SimpleFunc(num); return 0; } int SimpleFunc(int num) // 여기 { return num; // 여기 } 이렇게 3군데에서 메모리 공간이 할당되면서 동시에 초기화가 이루어진다. (C++에서 객체도 마찬가지) main 함수에서 int num = 10; 이 부분이야 당연히 알거고... int SimpleFunc(int num) 이 부분에서는 함수가 호출되고 매개변수로 선언된 변수들 메모리가 할당됨과 동시에 인자로 받아온 값으로 초기화가 된다. 문제는 SimpleFunc 함수 내부에 있는 return num; 이부분이다. 값을 return 할 때에도 메모리가 할당이 되고 동시에 리턴할 값으로 초기화가 이루어진다. (조금만 생각하면 당연한 일이다. 예를들어 문자열의 길이를 반환하는 함수를 만든다고 하면 매개변수로는 char *형을 넘겨줄거고 이 문자열의 길이를 세어서 반환은 int형으로 해줄텐데... 함수를 호출한 곳에서 값을 받으려면 어딘가에는 저장이 되어 있어야한다.) 그리고 이때 반환값은 값 복사(Call By Value)로 호출한 곳으로 전달이 된다.

[C] scanf 함수 char형 하나의 문자 입력받을 시 발생하는 문제

아래와 같은 코드를 실행시켜 보면 #include <stdio.h> int main(void) { char str[30] = {0}; char ch = 0; scanf("%s", str); scanf("%c", &ch); printf("%s\n", str); printf("%c\n", ch); return 0; } 사용자가 "abc"를 입력했을 경우 "abc"를 str에 입력받고나서 ch에 입력받을 문자를 사용자가 입력 하기를 기다려야 되는데 그냥 넘어가 버린다. 이유는 사용자가 "abc"를 입력할 때 입력되는 문자열은 정확하게는 "abc(enter)"이다. 이 때문에 str에 "abc"가 입력이되고 입력버퍼에는 "(enter)"가 남아있게 된다. (엔터가...) 그래서 ch에 하나의 문자를 입력받을 차례에 이 "(enter)"가 입력이 되어버리고 출력 결과에 보면 줄바뀜이 되는걸 확인할 수 있다. 이를 해결하기 위해서는 1. scanf( " %c" , &ch); 와 같이 %c 앞에 공백을 넣어준다. 2. getchar();를 scanf 사용전에 써서 getchar 함수가 엔터값을 입력 받도록 하면 된다. (아래로 전부 scanf 사용 전에 코드를 추가) scanf("%s", str); getchar(); scanf("%c", &ch); 3. fflush(stdin); 을 추가해서 입력 버퍼를 비워줘도 된다. 하지만 gcc에선 안 된다. scanf("%s", str); fflush(stdin); scanf("%c", &ch); 4. rewind(stdio); 를 추가. 정확한 원리...

[C] C언어의 메모리 구조 (스택, 힙, 데이터, 코드 영역)

출처 - http://blog.naver.com/PostView.nhn?blogId=sealriel&logNo=10121467341 C 언어의 메모리 구조는 크게 스택 영역(Stack Area), 데이터 영역(Data Area), 코드 영역(Code Area), 힙 영역(Heap Area)있다. 스택 영역(Stack Area) 스택 영역은 프로그램이 동작 시 지역변수, 매개변수, 표준버퍼, 시스템(OS) 임시데이터가 생성되고 사라지는 영역이다. 예를 들어 int, char, double, void, float 등 기본 자료형 과 if, for, while 등의제어문의 내부에서 선언된 변수는 제어문을 빠져나오면 수명이 다한다. 함수의 호출시 매개변수나, 함수의 내부에서 사용되는 지역변수도 마찬가지이다. 이러한 데이터들이 프로그램이 동작하는 동안 스택에서 생성과 소멸을 반복하고 있다. 스택은 순차적으로 데이터를 저장하고 꺼내는 LIFO(Last In First Out) 방식으로 동작하는데 가장 마지막에 생성된 데이터를가장 먼저 꺼내서 읽을 수 있다. 이러한 방식의 장점은 메모리의 공산을 낭비 없이 사용할 수 있다는 점과 메모리 영역에서 속도가 가장 빠르며, 동작방식의 특성상 순차적인 명령을 읽었다가 순차적으로 수행하는데 최적화 되어있다. 스택은 메모리의낮은 주소부터 시작하며, 힙 영역이 끝나는 곳에서 서로 만난다. 데이터 영역(Data Area) 데이터 영역은 전역변수와 정적변수(static) 변수가 저장되는 영역이다. 이 여역에 할당되는 변수들은 프로그램의 시작과 동시에 할당되어, 프로그램이 종료될 때 소멸된다. 따라서 전역변수와 정적변수는 프로그램이 종료 할 때까지 존재하는 변수들이다. 데이터 영역은 세부적으로 Data영역과 Bss영역으로 구분되기도하는데, Data 영역은 초기값을 가진 전역변수와 정적변수가 할당되는 공간이고...

[C] A.txt 내용을 정렬하여 B.txt로 출력

#include <stdio.h> #include <tchar.h> #include <Windows.h> int _tmain(int argc, LPTSTR argv[], LPTSTR *env) { system("sort < A.txt > B.txt"); return 0; }

[C] A.txt 내용을 정렬하여 콘솔에 출력

#include <stdio.h> #include <tchar.h> #include <Windows.h> int _tmain(int argc, LPTSTR argv[], LPTSTR *env) { system("sort < A.txt"); return 0; }

[C] Thread 사용 예제

#include <stdio.h> #include <tchar.h> #include <Windows.h> #include <process.h> #include <locale.h> unsigned WINAPI ThreadProc(LPVOID lpParam); // Thread Func 함수 형식이 반드시 이와 같아야 함. int _tmain(int argc, LPTSTR argv[]) { _tsetlocale(LC_ALL, _T("Korean")); // 유니코드에서 한글 출력을 위한 코드 DWORD dwThreadID[3] = {0}; HANDLE hThread[3] = {0}; for(int i = 0; i < 3; i++) { hThread[i] = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, (LPVOID)i, 0, (unsigned *)&dwThreadID[i]); // Thread 생성 if(hThread == NULL) { _tprintf(_T("Thread creation fault!\n")); return -1; } } WaitForMultipleObjects(3, hThread, TRUE, INFINITE); DWORD retVal = 0; GetExitCodeThread(hThread[0], &retVal); _tprintf(_T("첫번째 Thread return value[%d]\n"), retVal); GetExitCodeThread(hThread[1], &retVal); _tprintf(_T("두번째 Thread return value[%d]\n"), retVal); GetExitCodeThread(hThread[2], &retVal); _tprintf(_T("세번째 Th...

[C] 파일 속성의 만든 날짜, 수정한 날짜, 액세스한 날짜 얻고 수정하기

#include <stdio.h> #include <tchar.h> #include <Windows.h> #define STRING_LEN 100 int _tmain(int argc, LPTSTR argv[]) { TCHAR fileName[] = _T("data.txt"); TCHAR fileCreateTimeInfo[STRING_LEN] = {0}; TCHAR fileAccessTimeInfo[STRING_LEN] = {0}; TCHAR fileWriteTimeInfo[STRING_LEN] = {0}; FILETIME ftCreate = {0}, ftAccess = {0}, ftWrite = {0}; SYSTEMTIME stCreateUTC = {0}, stCreateLocal = {0}; SYSTEMTIME stAccessUTC = {0}, stAccessLocal = {0}; SYSTEMTIME stWriteUTC = {0}, stWriteLocal = {0}; HANDLE hFile = CreateFile(fileName, GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hFile == INVALID_HANDLE_VALUE) { _tprintf(_T("File open fault!\n")); return -1; } if(!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite)) { _tprintf(_T("GetFileTime function call fault!\n")); return FALSE; } FileTimeToSystemTime(&ftCreate, &stCreateUTC); SystemTimeToTzSpecificLocalTime(NULL, &stCr...

[C] 뇌를 자극하는 윈도우즈 시스템 프로그래밍 명령 프롬프트 프로젝트 코드

다운로드 내 생각대로 한거라 책 예제 코드와는 다름

[C] 특정 경로의 하위 레지스트리를 모두 출력

HKEY hKey = NULL; DWORD dwIndex = 0; DWORD dwSize = 0; DWORD cbName = MAX_PATH; DWORD dwType = REG_SZ; LSTATUS lStatus; TCHAR szKeyName[MAX_PATH] = {0}; TCHAR szKeyInfo[MAX_PATH] = {0}; CString strSubKey = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"); CString ErrorMsg; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, strSubKey, 0, KEY_ALL_ACCESS, &hKey) != ERROR_SUCCESS) { ErrorMsg.Format(_T("OpenKey Faild! : [ %s ]"), strSubKey); AfxMessageBox(ErrorMsg); ErrorMsg.Empty(); } else { while ((lStatus = RegEnumKeyEx(hKey, dwIndex, szKeyName, &cbName, NULL, NULL, NULL, NULL)) != ERROR_NO_MORE_ITEMS) { if (lStatus == ERROR_SUCCESS) { HKEY hItem = NULL; if (RegOpenKeyEx(hKey, szKeyName, 0, KEY_READ, &hItem) != ERROR_SUCCESS) { ErrorMsg.Format(_T("Can't open subkey : [ %s ]"), szKeyName); AfxMessageBox(ErrorMsg); ErrorMsg.Empty(); continue; } else { //_tprintf(_T("%s\n"), szKey...

[C] printf 함수의 매개변수 문자열 포맷 형식

이미지
https://msdn.microsoft.com/ko-kr/library/56e442dc.aspx printf("%0*d\n", 8, 23); 과 같이 사용하면 printf("%08d\n", 23); 과 동일한 결과를 보인다. 즉, 출력 시 자릿수를 동적으로 변경할 수 있다. (포맷 문자열 조작을 통해서가 아닌) 마찬가지로 printf("%-*d%d\n", 10, 1, 2); 이런 식으로 사용이 가능하다.

[C++] 연산자 우선순위

https://msdn.microsoft.com/ko-kr/library/126fe14k.aspx

[C++] typedef

출처 - http://www.benjaminlog.com/entry/typedef typedef BOOL int; typedef int BOOL; BOOL flag로 선언하면 int flag와 동일한 문장이 되게 하려면 둘 중 어느것으로 선언해야하나... 답은 아래 typedef int BOOL; 이 맞다. 이어서 다른 typedef 정의들을 보자면 typedef int BOOL, *PBOOL; typedef struct _student{ int stNo; int korScore; }student, *pstudent; typedef void (*pFunc)(int, int*); 위 3개의 typedef 정의를 보면 어디까지가 정의이고 어디가 그걸 대체하는 type인지 헷갈리기 시작한다. typedef를 정의할 때는 이를 헷갈리지 않기 위해 딱 한 가지만 기억하면 된다. "변수를 적어야 할 위치에 새로운 타입을 적어라." 위에 나왔던 typedef 들을 다시 하나씩 살펴보면... (빨강색은 타입, 파란색은 변수) int i ; int j , * p ; 이제 typedef를 다시 보면 typedef int BOOL ; typedef int BOOL , * PBOOL ; 이렇듯 변수명을 적어줄 위치에 대체할 타입명을 적어주면 이 타입명으로 대체가 가능하다. 구조체도 마찬가지로 struct _student{ int stNo; int korScore; } student ; 이렇게 선언하면 _student 구조체를 정의함과 동시에 student라는 변수명으로 구조체가 생성이된다. 위에 int j, *p; 이렇게 선언한 것처럼 struct _student{ int stNo; int korScore; } st , * pSt , ** ppSt ; 이렇게도 선언이 가능한데... "변수를 적어야 할 위치에 새로운 ...

[C++] 새로운 자료형 bool

bool 자료형은 C언어에는 없는 자료형이었으나 최근 표준에서는 bool도 C언어의 기본 자료형으로 추가되었다. C와 C++은 정수0은 '거짓'으로 그리고 0이 아닌 모든 정수는 '참'으로 정의한다. 하지만, bool 자료형을 사용하면 true와 false로 참과 거짓을 표현할 수 있다. true와 false를 출력하면 각각 1과 0으로 출력되는데 이 때문에 define 된 것으로 오해할 수가 있는데 정수형은 4byte, bool형은 1byte로 다르다. 다만 각각 1과 0으로 출력되는 것은 예전부터 쭉 그렇게 사용해왔고 아직도 그렇게 사용하고 있기 때문에 이 둘을 출력하거나 정수형으로 변환하면 1과 0으로 변환되도록 정의되어 있을 뿐이다.

[C++] const 참조자의 상수 참조

참조자를 const로 선언하면 상수 참조가 가능하다. const int &ref = 30; 이런 식으로 위처럼 하면 const 참조자가 상수를 참조할 때 임시변수를 만들어서 이 임시변수에 상수를 저장하고 이를 참조자가 참조하도록 한다. 따라서, int Adder(const int &num1, const int &num2) { return num1 + num2; } cout << Adder(3, 4) << endl; 위와 같은 코딩이 가능하다.