윤성우님께서 쓰신 "열혈 자료구조"를 보려고 너무 오랜만에 책을 펼쳤는데, 순간 당황했다.
c언어에서 사용되는 -> 기호가 무슨 뜻이었는지 기억이 가물 가물 하면서 기억나질 않았다. 그래서 당황해서 급하게 서현우씨께서 쓰신 "이것이 c언어다" 책을 펼쳤다. (기억이 안날만도 하다. 2년의 공백이 너무 컸다.)
지금 4년 만에 다시 펼쳐보는 것 같다. 기본기를 소홀히 한 대가다. 요즘 들어서 느끼는 게 있는데, 아무리 서비스 위주의 기술들 중에서 핫한 기술들이 뜨고 이것저것 나오더라도 기본기는 언제나 중요하다는 것을 느낀다. 아무리 빠르고, 성능 좋은 라이브러리라 하더라도 c++과 c를 기반으로 작성되어있는 경우가 많았고, 성능이라는 면에서 아직도 이 둘을 따라올 언어가 없다고 생각한다. 그러니 기초적으로 반드시 알고 있어야 한다고 생각한다. (근데 기억이 가물가물하니 대참사)
생산성을 주목한다면 얘기가 달라지겠지만, 비즈니스 모델은 시간이 흐르면 흐를수록, 생산성보다는 안정성과 뛰어난 성능에 집착할 수 밖에 없기 때문에 다시 초심으로 돌아오기 마련이라고 생각한다. 뭐 아무튼 그렇고... 다시 back to the past... 다시 공부하자. 기억날때까지
그리고 사실 앞의 모든 이유를 제외하고서라도, 기본기에 충실하자는 말은 모든 분야에 해당되는 말이니, 다시 예전공부 해봐도 손해볼일은 없을 듯 싶다.
#include<stdio.h>
void input_ary(double* pa, int size);
double find_max(double* pa, int size);
int main(void){
double ary[5];
double max;
int size = sizeof(ary) / sizeof(ary[0]);
input_ary(ary, size);
max = find_max(ary, size);
printf("배열의 최댓값 : %lf", max);
return 0;
}
void input_ary(double* pa, int size) {
int i;
printf("%d개의 실수값 입력 : ", size);
for (i = 0; i < size; i++) {
scanf_s("%lf", pa + i);
}
}
double find_max(double* pa, int size) {
double max;
int i;
max = pa[0];
for (i = 1; i < size; i++) {
if (pa[i] > max) max = pa[i];
}
return max;
}
구조체 완전 기본
#include<stdio.h>
struct student {
int num;
double grade;
};
int main(void) {
struct student s1;
s1.num = 2;
s1.grade = 2.7;
printf("학번 : %d\n", s1.num);
printf("학점 : %.1lf\n", s1.grade);
return 0;
}
malloc 동적 할당 기본
#include<stdio.h>
#include<stdlib.h>
int main(void) {
int* pi;
double* pd;
pi = (int*)malloc(sizeof(int));
if (pi == NULL) {
printf("#으로 메모리가 부족합니다. \n");
exit(1);
}
pd = (double*)malloc(sizeof(double));
//malloc 함수는 (void*) 형을 반환하므로 용도에 맞는 포인터형으로 형변환하여 사용합니다.
*pi = 10;
*pd = 3.4;
printf("정수형으로 사용 : %d\n", *pi);
printf("실수형으로 사용 : %lf\n", *pd);
free(pi);
free(pd);
//동적으로 할당한 저장공간은 함수가 반환된 후에도 자동으로 회수되지 않습니다.
//따라서 반환되기 전에 free함수로 직접 반환해야 합니다.
return 0;
}
매개변수로 구조체 넘기기
#include<stdio.h>
struct vision {
double left;
double right;
};
struct vision exchange(struct vision);
int main(void) {
struct vision robot;
printf("시력 입력 : ");
scanf_s("%lf%lf", &(robot.left), &(robot.right));
robot = exchange(robot);
printf("바뀐 시력 : %.1lf,%.1lf \n", robot.left, robot.right);
return 0;
}
struct vision exchange(struct vision robot) {
double temp;
temp = robot.left;
robot.left = robot.right;
robot.right = temp;
return robot;
}
비트필드 구조체
구조체 포인터
구조체 배열
자기 참조 구조체
공용체
열거형
typedef
구조체 포인터
#include<stdio.h>
struct score {
int kor;
int eng;
int mat;
};
int main(void) {
struct score yuni = { 90,80,70 };
struct score* ps = &yuni;
printf("%d \n", ps->kor);
printf("%d \n", ps->eng);
printf("%d \n", ps->mat);
return 0;
}
구조체 포인터 연결 리스트
#include<stdio.h>
struct list {
int num;
struct list* next;
};
int main(void) {
struct list a = { 10,0 }, b = { 20,0 }, c = { 30,0 };
struct list* head = &a, * current;
a.next = &b;
b.next = &c;
printf("head->num : %d \n", head->num);
printf("head->next->num : %d \n", head->next->num);
printf("list all : ");
current = head;
while (current != NULL) {
printf("%d ", current->num);
current = current->next;
}
printf("\n");
return 0;
}
union 공용체
#include<stdio.h>
union student {
int num;
double grade;
};
int main(void) {
union student s1 = { 315 };
printf("학번 : %d\n", s1.num);
s1.grade = 4.4;
printf("학점 : %.1lf\n", s1.grade);
printf("학번 : %d\n", s1.num);
return 0;
}
결과:
공용체는 모든 멤버가 하나의 저장공간을 같이 사용합니다.
공용체 변수의 크기는 멤버 중에서 크기가 가장 큰 멤버로 결정됩니다.
num과 grade 멤버가 하나의 공간을 공유합니다.
공용체 변수의 초기화는 중괄호를 사용하여 첫번째 멤버만 초기화합니다.
그렇기 때문에 공용체 멤버는 언제든지 다른 멤버에 의해 값이 변할 수 있으므로 항상 각 멤버의 값을 확인해야 하는 단점이 있습니다. 하지만 여러 멤버가 하나의 저장 공간을 공유하므로 메모리를 절약할 수 있고, 특히 같은 공간에 저장된 값을 여러가지 형태로 사용할 수 있는 장점이 있습니다.
열겨형
#include<stdio.h>
enum season {SPRING,SUMMER,FALL,WINTER};
int main(void) {
enum season ss;
char *pc;
ss = SPRING;
switch (ss) {
case SPRING:
pc = "inline"; break;
case SUMMER:
pc = "swimming"; break;
case FALL:
pc = "trip"; break;
case WINTER:
pc = "skiing"; break;
}
printf("나의 레저 활동 => %s\n", pc);
return 0;
}
열겨형은 변수에 저장할 수 있는 정수값을 기호로 정의하여 나열합니다.
typedef 형재정의
#include<stdio.h>
typedef struct {
int num;
double grade;
}Student;
void print_data(Student* ps);
int main(void) {
Student s1 = { 315,4.2 };
print_data(&s1);
return 0;
}
void print_data(Student * ps) {
printf("학점 : %d\n", ps->num);
printf("학점 : %.1lf\n", ps->grade);
}
typedef 으로 재정의 예제
#include<stdio.h>
typedef union {
int ea;
double kg;
double liter;
}Unit;
typedef struct {
char name[20];
enum { EGG = 1, MILK, MEAT } kind;
Unit amount;
}Gift;
void print_list(Gift a);
int main(void) {
Gift list[5];
int i;
for (i = 0; i < 5; i++) {
printf("이름 입력: ");
scanf_s("%s", list[i].name);
printf("품목 선택(1.계란, 2.우유, 3.고기) : ");
scanf_s("%d", &list[i].kind);
switch (list[i].kind) {
case EGG: list[i].amount.ea = 30; break;
case MILK: list[i].amount.liter = 4.5; break;
case MEAT: list[i].amount.kg = 0.6; break;
}
}
printf("# 세번째 경품 당첨자... \n");
print_list(list[2]);
return 0;
}
void print_list(Gift a) {
printf("이름 : %s, 선택 품목 : ", a.name);
switch (a.kind) {
case EGG: printf("계란 %d개\n", a.amount.ea); break;
case MILK: printf("우유 %.1lf리터\n", a.amount.liter); break;
case MEAT: printf("고기 %.1lfkg\n", a.amount.kg
); break;
}
}
#define
#include<stdio.h>
#define PRINT_EXPR(x) printf(#x " = %d\n",x)
#define NAME_CAT(x,y) (x##y)
// #은 매크로 함수의 인수를 문자열로 치환하고, ##은 두 인수를 붙여서 치환합니다.
int main(void){
int a1, a2;
NAME_CAT(a,1) = 10;
NAME_CAT(a,2) = 20;
PRINT_EXPR(a1+a2);
PRINT_EXPR(a2-a1);
return 0;
}
#include<stdio.h>
#define VER 7
#define BIT16
int main(void){
int max;
#if VER >6
printf("버전 %d 입니다. \n",VER);
#endif
#ifdef BIT16
max = 32767;
#else
max = 2147483647;
#endif
printf("int형 변수의 최댓값 : %d\n",max);
return 0;
}
#include<stdio.h>
#define VER 7
#define BIT16
int main(void){
int max;
#if VER >6
printf("버전 %d 입니다. \n",VER);
#endif
#undef BIT16
#ifdef BIT16
max = 32767;
#else
#error BIT16 이 정의되어있어야 합니다.
#endif
printf("int형 변수의 최댓값 : %d\n",max);
return 0;
}
#pragma 지시자
#include<stdio.h>
#pragma warning(disable:4996) //4996번 경고 메시지는 모두 표시하지 않음.
#pragma pack(push,1) //바이트 얼라인먼트를 1로 바꿈
typedef struct{
char ch;
int in;
}Sample1;
#pragma pack(pop) //바꾸기 전의 바이트 얼라인먼트 적용
typedef struct{
char ch;
int in;
}Sample2;
int main(void){
printf("Sample1 구조체의 크기 : %d 바이트\n",sizeof(Sample1));
printf("Sample2 구조체의 크기 : %d 바이트\n",sizeof(Sample2));
//Sample1 구조체의 크기 : 5 바이트
//Sample2 구조체의 크기 : 8 바이트
return 0;
}
visual studio 2019를 써서 컴파일 했는데, cpp 컴파일에서 해서 그런지 예제들 따라해보면서 자잘한 워닝이 자주 떴다. 마지막 예제같은 경우는 작동도 되지 않았다. 그래서 dev c++를 사용해서 c파일로 만들어서 작성해주니 잘 작동하더라.
c 공부할 때는 그냥 dev 사용하는 게 더 좋을 듯 하다.
커뮤니티를 보면 visual studio에서 c 컴파일러 완벽히 지원안하네 어쩌네 댓글로 본적이 몇 번있었는데, 그것때문에 그런건가 싶기도 하다. 물론 표준 탓하기 이전에 내 코드가 맞는건지 확인하는 게 먼저인듯싶다.
'C & C++ > C' 카테고리의 다른 글
[C] 메모리와 변수의 lifetime으로 인한 예상치 못한 결과 (0) | 2021.10.08 |
---|---|
[Linux] Ubuntu c programming - file open /read /write (0) | 2021.09.30 |
[C] C언어 세그멘테이션 오류 (코어 덤프됨) (0) | 2021.09.29 |
[Linux] fcntl.h와 unistd.h (0) | 2021.09.14 |
[C] void main(), int main(), main() 차이점 (0) | 2021.07.03 |