일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- c# 윈폼
- Flutter
- 깃
- 플러터
- 포인터
- docker
- github
- C# delegate
- c# 추상 클래스
- 구조체
- c언어
- Unity
- C언어 포인터
- dart 언어
- HTML
- gitlab
- git
- 다트 언어
- Python
- 도커
- Data Structure
- Houdini
- C++
- Algorithm
- vim
- c#
- jupyter lab
- jupyter
- 유니티
- c# winform
- Today
- Total
목록Programming/C (54)
nomad-programmer
typedef 는 타입을 정의한다는 의미의 "type define"의 줄임 표현이다. 기존의 자료형 중에 자료형 이름의 길이가 긴 경우 프로그래머가 짧고 간결하게 자료형을 재정의하는 문법이다. #define과 비슷해 보이지만 #define은 치환 작업을 수행하는 전처리기이고 typedef는 기존 자료형을 다른 이름으로 새롭게 정의하는 기능이다. 기존 자료형을 단순한 형태의 새 자료형으로 typedef 문법이 가장 흔하게 사용되는 경우는 기존 자료형의 이름이 너무 길어서 새로운 자료형으로 재정의해야 할 때이다. typedef unsigned short int US; // unsigned short int temp; 라고 선언한 것과 같다. US temp; 새롭게 정의했다는 의미를 전달하게 위해 새로 정의한..
https://nomad-programmer.tistory.com/87 [C] 2차원 배열 같은 2차원 포인터의 동적 할당 열의 개수가 행 별로 각기 다르다면 2차원 배열로 생성할 시 메모리 낭비가 불가피하다. 허나, 2차원 포인터로 동적 할당하여 2차원적으로 구조를 생성하면 메모리를 낭비하지 않는 타이트한 메� nomad-programmer.tistory.com 위의 2차원 포인터 동적 할당 포스터중의 예제에서 확장한 것이다. #include #include int main(void) { unsigned int*** arr3d; unsigned int cnt3d; unsigned int cnt2d; unsigned int cnt1d; unsigned int temp; fputs("x축 개수: ", st..
열의 개수가 행 별로 각기 다르다면 2차원 배열로 생성할 시 메모리 낭비가 불가피하다. 허나, 2차원 포인터로 동적 할당하여 2차원적으로 구조를 생성하면 메모리를 낭비하지 않는 타이트한 메모리 구조를 생성할 수 있다. #include #include int main(void) { unsigned int** arr2d; unsigned int cnt2d; unsigned int cnt1d; unsigned int temp; fputs("x축 개수: ", stdout); scanf_s("%d", &temp); arr2d = (int**)malloc(temp * sizeof(int*)); //cnt2d = temp; 아래의 연산과 같음. heap영역에 동적 할당하여 _msize함수 사용 cnt2d = (_ms..
#include #include #include #include void SetData(unsigned short** dst, unsigned short** src, const short size) { for (int i = 0; i < size; i++) { *(*(dst)+i) = *(*(src)+i); } } void Push(unsigned short** ptr, short* curt, const short value) { (*curt)++; unsigned short* new_data = (unsigned short*)malloc(((*curt) + 1) * sizeof(short)); SetData(&new_data, ptr, *curt); *(new_data + (*curt)) = value..
#include #include int main(void) { // depth가 2, 행이 3, 열이 4인 배열을 동적 할당으로 heap 영역에 할당. char (*data)[3][4] = (char***)malloc(sizeof(char) * 2 * 3 * 4); for (int i = 0; i < (2 * 3 * 4); i++) { *(*(*(data + (i / (3 * 4))) + ((i / 4)) % 3) + (i % 4)) = i; } for (int i = 0; i < (2 * 3 * 4); i++) { printf("%-2d ", *(*(*(data + (i / (3 * 4))) + ((i / 4)) % 3) + (i % 4))); if ((i % 4) == 3) { puts(""); } ..
#include int main(void) { char data[3][5] = { {0,}, {0,}, {0,} }; // 2차원 배열의 주소를 저장할 수 있는 포인터 char (*ptr)[5] = data; /* char형 주소값 2개를 저장할 수 있는 배열 */ // char* ptr2[2] = { &data[0][0], &data[1][2] }; // 위의 코드와 같은 초기화 선언이다. char* ptr2[2] = { &(*(*(data+0)+0)), &(*(*(data+1)+2)) }; // data[1][1]에 5저장 (*(ptr+1))[1] = 5; // data[2][0]에 77저장 ptr[2][0] = 77; // data[2][1]에 99저장 *(*(ptr + 2) + 1) = 99; /..
#include int main(void) { int arr[2] = { 0x12345678, 0x12345678 }; printf("%-20s: %p, %p\n", "original", arr[0], arr[1]); // 이렇게 인덱스로만 값을 대입시키면 4바이트 전체가 변경된다. arr[1] = 0x01; printf("%-20s: %p, %p\n", "arr[1]", arr[0], arr[1]); // 1바이트만 변경할 것이라 char 포인터형으로 변경 (char*)arr[1] = 0x01; printf("%-20s: %p, %p\n", "(char*)arr[1]", arr[0], arr[1]); // 1바이트만 변경할 것이라 char 포인터형으로 변경. (char*)arr[1] 과 같은 뜻. *(..
#include #include #include // 최대 길이 설정하여 arr에 문자열 저장 int GetString(char* arr, int limit) { for (int i = 0; i < limit; i++) { arr[i] = getchar(); if (arr[i] == '\n') { arr[i] = '\0'; return 1; } } // 표준 입력 버퍼를 비운다. rewind(stdin); arr[0] = '\0'; return 0; } // atoi 함수의 기능을 새롭게 정의하였다. int Str2Num(char* arr) { int res = 0; int cnt = 0; while (arr[cnt] != '\0') { res = (res * 10) + (arr[cnt] - '0'); ..
대상의 크기가 정해져 있지 않은 void *형 포인터 대상의 크기를 모른다면? 이때 사용하는 것이 바로 void 키워드이다. void 키워드는 '정해져 있지 않다'는 의미를 가지고 있다. void* ptr; 이렇게 선언하면 ptr에 주소 값을 저장할 수는 있지만 해당 주소에서 값을 읽거나 저장할 때 사용하는 크기는 정해져 있지 않다. 즉 사용할 메모리의 시작 주소만 알고 끝 주소를 모를 때 사용하는 포인터 형식이다. void 포인터는 가리킬 대상의 크기를 정한 것이 아니라서 어떤 크기의 메모리가 오든지 상관 없다. 그렇다면 void * 로 선언한 포인터 변수를 주소 값만 저장하는 용도로 사용하는 것은 아니다. 적절한 형 변환을 거쳐 '사용할 크기'를 표기해 주면 일반 포인터처럼 사용할 수 있다. int ..
// 총 4바이트 0x12345678 빅 엔디안 - 리눅스, 유닉스 등은 빅 엔디안 방식이다. 큰 수의 비트부터 읽어 들이고 메모리에 저장할 때도 마찬가지로 큰 비트를 먼저 메모리에 올린다. 즉, 위의 16진수 같은 값이 있다면 0xAAA1 주소에 0x12가 올라가고 그 다음 0xAAA2 주소에 0x34 값이 올라가고 그 다음 0XAAA3 주소에 0x56 값이 올라가고 마지막 0x78은 0xAAA4 주소에 올라간다. 0xAAA4 0x78 0xAAA3 0x56 0xAAA2 0x34 0xAAA1 0x12 위의 표 처럼 메모리에 올라간다. 리틀 엔디안 - 윈도우즈는 리틀 엔디안 방식이다. 작은 수의 비트부터 읽어 들이고 메모리에 저장할 때도 마찬가지로 작은 비트를 먼저 메모리에 올린다. 0xAAA4 0x12 ..
// 일반 변수 상수화: tmp변수는 10이라는 값을 가지고 다른 값을 가질 수 없도록 상수화한다. const int tmp = 10; // 포인터 상수화 // 대상을 상수화: ptr 포인터가 tmp로 접근하여 tmp의 값을 변경하지 못하도록 상수화. 즉, // *ptr 연산으로 tmp 값을 변경하지 못한다. const int * ptr = &tmp; // 자신을 상수화: ptr 포인터는 오직 tmp의 주소 값을 가리킨다. 다른 주소를 가리키지 못하도록 상수화한다. int * const ptr = &tmp; // tmp의 주소만 가리킬 수 있고 tmp의 값을 변경하지 못한다. const int * const ptr = &tmp;
fgets 함수를 사용하여 문자열을 stdin으로 받는다고 생각해보자. 이때 fgets 함수가 받을 수 있는 길이보다 입력한 문자열이 더 길 경우, fgets 함수는 자기가 받을 수 있는 만큼만 받아 변수에 그 값을 넣어주고 끝난다. 그럼 이때 stdin 버퍼에는 입력 받고 남은 문자 찌꺼기들이 남아있다. 이것을 비워줘야 문제가 발생하지 않는다. 아래의 예제를 살펴보자. stdin 버퍼에 남아있는 문자들을 \n 문자가 나올 때까지 무한루프를 돌고 있다. 어째서 \n 문자일까? 이것은 키보드에서 Enter가 나올때까지 입력 스트림에서 버퍼로 저장되기 때문이다. 즉 \n이 마지막에 존재할 것이다. 그래서 \n 문자가 나올 때까지 무한루프를 돌리면 입력 버퍼는 깨끗이 비워진다. 입력 버퍼를 비우지 않아 예상치..
scanf 함수와 scanf_s 함수 scanf 함수를 쓰게되면 경고 메시지가 나온다. scanf 대신 scanf_s 함수를 사용하라는 경고. 그 이유는 기존에 사용하던 scanf 함수가 구조적으로 안정적이지 않아 여러 위험을 안고 있는 함수이기 때문이다. 이러한 문제점을 보완하여 나온 함수가 scanf_s 함수이다. 그래서 scanf_s 함수를 사용하도록 컴파일러가 권장하고 있다. scanf 함수에서 scanf_s 함수로 달라진 점은? 기존 scanf는 char 형이나 문자열을 넣을 때 받을 수 있는 문자열의 사이즈를 넣지 않아도 사용이 가능했다. 그로 인해 사용자가 실수로 받을 수 있는 길이의 문자열을 초과하여 입력하면 스택오버플러우 에러가 발생했다. 이런 경우를 사전에 예방하자는 차원에서 나온 것이..
// 2진수 ex) 0000 0000 1010 0111 풀이1) (2의 7승) + (2의 5승) + (2의 2승) + (2의 1승) + (2의 0승) 풀이2) 127 + 32 + 4 + 2 + 1 결과) 166 // 8진수 ex) 074 풀이1) (8의 1승) * 7 + (8의 0승) * 4 풀이2) (8 * 7) + (1 * 4) 결과) 60 // 10진수 ex) 78 풀이1) (10의 1승) * 7 + (10의 0승) * 8 풀이2) (10 * 7) + (1 * 8) 결과) 78 // 16진수 ex) 0x00A3 풀이1) (16의 1승) * A + (16의 0승) * 3 풀이2) (16 * 10) + (1 * 3) 결과) 163