티스토리 뷰
구조체와 연결 리스트
typedef 문법
프로그래머가 기존의 자료형을 짧고 간결하게 정의할 때 사용한다.
자료형을 단순한 형태의 새 자료형으로 바꾸기
typedef unsigned short int US; //unsigned short int를 US로 재정의
US temp; //재정의한 자료형을 사용하기
typedef의 장점
복잡해 보이는 문법을 쉽게 표현할 수 있다.
- 일반 변수 형식뿐만 아니라 배열, 포인터 형식도 재정의 가능하다.
typedef int MY_DATA[5];
MY_DATA temp;
typedef 사용 여부 확인 방법
재정의한 자료형 위에 마우스를 올려 놓으면 정의를 쉽게 확인 가능
typedef의 장점
int (*p)[5]; 20바이트의 사용 범위를 가지는 포인터 변수 선언한 것이다.
연산자 우선순의 때문에 괄호까지 사용하여 복잡해 보인다.
문법을 좀더 명시적으로 표현하기 위해 사용 typedef을 사용해 나타내보면
typedef int MY_DATA[5];
MY_DAYA *p;
으로 표현할 수 있다. 자료형의 크기를 쉽게 바꿀 수 있다.
데이터를 그룹으로 묶는 구조체
비슷한 형태의 데이터를 관리하려면 변수를 개별적으로 선언해야 한다. 그렇게 되면 작성해야 하는
코드가 많아지게 된다.
데이터의 그룹화1 : 배열
같은 자료형의 데이터를 묶어서 관리가 가능하다. 각 요소에 값을 대입하거라 읽을 때 index를 사용하면 된다. 이 index는 상수와 변수 모두 사용가능하다.
배열에서 데이터 관리를 하기 위해서 반복문을 이용하면된다.
int age[5];
float height[5];
int i;
for(i = 0; i < 5; i++) scanf("%d %f", age[i], height[i];); // 5번 반복하여 나이와 키를 입력받음.
배열을 이용해 데이터를 그룹시 한계가 있다. 크기가 동일한 데이터만 그룹으로 묶을 수 있다는 것이다.
데이터의 그룹화 2 : 구조체
크기나 형식이 다른 데이터를 그룹으로 묶어서 사용할 수 있는 문법이다. 기본 자료형이나 사용자 정의 자료형(typedef)을 그룹으로 묶어 새로운 자료형 만들 수 있다. 다양한 형태의 메모리 구조 생성한다.
구조체를 사용하는 이유가 배열로 데이터를 표현시 다양한 데이터 타입의 변수들을 관리하는데 한계가 있기 때문이다. 구조체는 타입이 다른 변수들의 집합이라 생각하면 된다. 예를 들어 한 사람의 신상 정보를 표현하고자 한다면 이름, 나이, 키, 혈액형 등 여러 정보들이 필요하다.
char name[10];
char blood[2];
int age;
double height;
name은 이름을 저장하는 문자열, blood는 혈액형을 저장하는 문자열, age는 나이를저장하는 정수형 변수, height는 키를 저장하는 실수형 변수이다. 각 변수들의 타입이 서로 다르기에 이 변수들을 묶을 수 없다. 이와 같이 관련성이 있는 정보들을 하나로 묶으려할 때 사용하는 타입이 구조체이다.
구조체로 새로운 자료형 만들기
struct 키워드 : 컴파일러에게 구조체임을 알리는 역할을 한다.
구조체 이름 : 새로 정의할 자료형의 이름
중괄호 { } 안에 자료형을 구성할 요소들을 나열하면 된다.
구조체의 크기는 모든 바이트들의 합 22바이트
(name 12바이트 + 나이 2바이트 + 키 4바이트 + 몸무게 4바이트)
구조체로 만든 자료형으로 변수 선언하기
구조체로 만든 자료형의 크기
struct 문법을 사용해 만든 자료형은 변수 선언 시 매번 struct를 붙여야 한다.
typedef을 이용하면 struct 키워드 적지 않고 변수 선언 가능하다.
struct People data;
struct People friend_list[64];
struct People *p
struct People{
char name[12];
unsigned short int age;
float height;
float weight;
}
typedef struct People Person; //구조체 People을 Person이란 타입으로 선언하다.
Person data; //data라는 변수를 선언
Person friend_list[64];
Person *p;
struct 와 typedef를 조합해서 구조체 변수를 선언하는 방법
struct와 typedef를 조합하여 문법을 표현
코드가 훨씬 간단해지고, 의미도 좀더 확실하게 부여 가능하다. 또 구조체 이름 없이 Person으로
사용 가능
typedef struct People{
char name[12];
unsigned short int age;
float height;
float weight;
} Person;
or
typedef struct {
char name[12];
unsigned short int age;
float height;
float weight;
} Person;
가용할 요소의 이름을 직접 적어야한다. 각 요소의 크기가 전부 다르고, 배열에서 사용되는 index 개념을 사용할 수 없다.
그래서 구조체안의 자료형들을 사용하고 싶다면 .(요소 지정) 연산자 사용하면 된다.
typedef struct People{
char name[12];
unsigned short int age;
float height;
float weight;
} Person;
void main() {
Person data;
data.age = 12;
data.height = 178.3;
}
Person 구조체의 메모리 크기는 22바이트이다.
구조체 자료형을 배열 변수로 선언한 경우
각 요소에 접근하는 방식은 동일하다. 변경하려는 배열 요소의 index를 [] 안에 적으면 된다.
.(요소 지정) 연산자를 사용하여 구조체에 표함된 요소를 사용한다.
Person friends[3]; // Person 데이터 3개를 저장할 수 있는 메모리를 할당
friends[1].age = 22; // 두 번째 요소의 age에 값 22을 대입
구조체로 선언한 변수의 요소를 포인터로 사용하기
Person data; //Person 자료형으로 data 변수를 선언
Person *p; //Person 형식으로 선언한 메모리에 접근할 수 있도록 포인터 선언
p = &data; //포인터 변수 p는 data 변수의 주소 값을 저장함.
(*p).age = 22; //포인터 p가 가리키는 data 변수의 요소 중 age에 22를 대입
구조체 변수를 구조체 *형으로 선언한 포인터 변수에 저장하여 사용 가능
*(주소 지정) 연산자를 사용하여 이동한 후, .(요소 지정) 연산자를 사용해야 한다.
연산자 우선 순위로 인하여 (*p).age = 22; 처럼 사용해야 한다.
이를 간단하게 표현하기 위해 -> 연산자를 사용한다.
Person data; //Person 자료형으로 data 변수를 선언
Person *p; //Person 형식으로 선언한 메모리에 접근할 수 있도록 포인터 선언
p = &data; //포인터 변수 p는 data 변수의 주소 값을 저장함.
p -> age = 22; //(*p).age = 22;와 동일한 표현
구조체 문법으로 선언한 변수의 초기화 방법
구조체 문법도 배열과 동일한 방식으로 초깃값 대입한다.
구조체 변수 선언 시 초기화 하려면 중괄호 {} 를 사용하여 초기값을 대입한다
구조체 내부에 선언한 변수와 초기값의 순서가 같아야 한다.
struct People {
char name[12];
unsigned short int age;
float height;
float weight;
}
void main () {
struct People data = {"홍길동", 51, 185.6, 86.3};
}
구조체로 만든 자료형의 크기
구조체 멤버 정렬 기준
구조체 요소를 일정한 크기로 정렬하여 실행속도를 더 빠르게 하는 개념
정렬 기준 : 1, 2, 4, 8 바이트
구조체 정렬 기준에 따라 구조체로 만든 자료형의 크기가 달라짐
-> 단순히 요소의 크기를 합산하여 구조체 크기로 사용하면 버그 발생
struct Test{
char a;
int b;
short c;
char d;
} => 전체 바이트는 8바이트
2바이트 정렬
각 요소는 2의 배수에 해당하는 주소에서 시작, 전체 크기 2의 배수
요소가 놓일 주소가 2의 배수가 아닌 경우
-> 1바이트를 버리고 2의 배수의 위치에 놓인다.
요소의 자료형이 2바이트보다 작은 경우 해당 요소의 크기로 정렬된다.
-> 2, 4, 8 바이트 자료형의 요소들은 2의 배수에 해당하는 주소에 배치
-> 1바이트 자료형 요소들은 그대로 1바이트 정렬된다
버려진 공간
4바이트 정렬
각 요소는 4의 배수에 해당하는 주소에서 시작, 전체 크기 4의 배수
요소가 놓일 주소가 4의 배수가 아닌 경우
-> 1 ~ 3바이트를 버리고 4의 배수의 위치에 놓인다.
요소의 자료형이 3바이트보다 작은 경우 해당 요소의 크기로 정렬된다.
-> 4, 8바이트 자료형의 요소들은 4의 배수에 해당하는 주소에 배치
-> 1바이트 자료형은 1바이트 정렬, 2바이트 자료형은 2바이트 정렬
버려진 공간
모든 요소가 기준 정렬 바이트보다 작으면 요소 중 가장 큰 요소의 크기로 정렬된다.
Test 구조체의 가장 큰 요소의 크기를 8바이트 기준으로 정렬하기 위해 double 타입을 사용하자.
struct Test {
char a;
구조체 멤버 정렬 기준을 설명할 예시 double b;
short c;
char d;
};
8바이트 정렬
각 요소는 8의 배수에 해당하는 주소에서 시작, 전체 크기 8의 배수
요소가 놓일 주소가 8의 배수가 아닌 경우
-> 1 ~ 7 바이트를 버리고 8의 배수의 위치에 놓인다.
요소의 자료형이 8바이트보다 작은 경우 해당 요소의 크기로 정렬된다.
-> 8 바이트 자료형의 요소들은 8의 배수에 해당하는 주소에 배치
-> 1, 2, 4 바이트 자료형은 각각 1, 2, 4 정렬 적용
Test 구조체의 8바이트 기준으로 정렬한 크기 : 24바이트
위에서 알아본 결과 구조체의 요소는 같은 크기끼리 모아 주는 것이 프로그램의 효율에 좋은 영향을 미친다.
데이터 크기가 같은 것끼리 묶어주는 것이 메모리 낭비를 막아주기 때문이다.
기존 구조체 A와 개선된 구조체 B에서 사용된 메모리들 간 차이는 8바이트로 구조체 B가 효율적이다.
컴파일러 설정에 따라 구조체로 선언한 자료형의 크기가 바뀔 수 있다. 구조체 크기는 직접적으로 계산하기
보다는 sizeof 연산자 사용이 안전하다.
파일 입출력
표준 입출력 라이브러리
표준 입출력 라이브러리
보조기억 장치에 파일 단위로 데이터를 저장하거나 읽을 수 있다.
많은 운영체제에서 표준 입출력 라이브러리를 제공하기 때문에 호환성이 높다.
운영체제에 상관없이 같은 이름의 함수로 보조기억 장치를 사용하는 프로그램을 개발 가능하다.
데이터의 형식에 따라 다른 함수를 제공한다.
바이너리 속성과 문자열 속성
char temp [8] = { 'a', 'b', 'c', 0};
두 속성의 차이점 살펴보기
1. 변수에 저장된 데이터의 크기를 구할 때 차이점
바이너리 속성 => int data_size = sizeof(temp);
문자열 속성 => int data_size = strlen(temp);
2. 변수에 저정된 값을 다른 변수에 복사할 때의 차이점
바이너리 속성
char temp[8] = { 'a', 'b', 'c', 0 };
char test [8];
//temp에서 test로 8바이트 크기 만큼 메모리를 복사
memcpy(test, temp, sizeof(temp));
문자열 속성
char temp[8] = { 'a', 'b', 'c', 0 };
char test[8] ;
//temp에서 test로 4바이트 크기(NULL 포함)만큼 복사
strcpy(test, temp);
바이너리 파일과 텍스트 파일
바이너리 파일은 바이너리 속성이 적용된 파일이다.
이미지 파일, 음악 파일, 동영상 파일, 실행 파일등이 속해 있다.
텍스트 파일은 문자열 속성이 적용된 파일이다.
간단한 문서 파일, 소스파일이 속해 있다.
파일 입출력 함수의 도우미! FILE 구조체
FILE 구조체
사용하려는 디스크상의 파일이 어떤 상태로 사용 중인지에 대한 정보를 담고 있으며,
파일을 좀 더 편하게 사용하도록 도와준다.
표준 입출력 라이브러리에서 파일 입출력 함수를 호출할 때마다 FILE 구조체의 포인터 변수를 넘겨주도록
구성되어 있다.
FILE *p_file;
//파일 열기 생략
fseek(p_file, 0, SEEK_SET);
파일 열기 함수 : fopen
함수 원형 : FILE *fopen(const char *filename, const char * mode);
함수 사용 형식 : fopen(사용할 파일 이름, 모드)
반환값
파일을 성공적으로 열면 FILE * 형식의 메모리 주소 값을 반환
파일이 존재하지 않거나 파일 형식을 잘못 사용하여 파일 열길에 실패하면 NULL 값을 반환
FILE *p = fopen("test.dat", "r");
if(NULL != p) {
//성공 경우
}
else {
//실패한 경우
}
FILE *p = fopen("C\test.dat","r");
if(NULL != p) {
//성공 경우
}
else {
//실패한 경우
}
파일 사용 형식 알아보기
파일 사용 형식
t 형식
텍스트 속성으로 파일을 사용하겠다는 뜻
t 형식으로 바이너리 파일을 열면 파일 열기는 성공하지만 파일 입출력 함수를 사용하면 오류 발생
b 형식
바이너리 속성의 파일을 사용한다는 뜻
형식을 따로 지정하지 않는다면 b 형식이 기본 값
r 형식
파일의 내용을 읽기 위한 목적으로 파일을 연다.
파일이 없는 경우 파일 열기에 실패하고 NULL을 반환
FILE *p = fopen("test.dat", "rb"); //rb대신 r 만 사용 가능
FILE *p = fopen("test.txt", "rt");
w 형식
파일에 데이터를 쓰기 위한 목적으로 파일을 연다.
파일이 없는 경우 그 이름으로 파일을 만든 후에 파일을 연다
같은 이름의 파일이 이미 있는 경우 파일을 열면서 파일 내용을 삭제
디스크에 용량이 부족하거나 CD와 같이 읽기 전용 디스크에 쓰기 모드로 사용하면 파일 열기에 실패
FILE *p = fopen("test.dat", "wb"); //wb대신 rw만 사용 가능
FILE *p = fopen("test.txt", "wt");
파일 사용 형식에서 읽기와 쓰기를 같이 사용하기
읽기 강조 " r+ "
읽기와 쓰기를 같이 사용할 때 읽기를 더 강조하는 형식
기존 파일이 없으면 파일을 새로 만들지 않고 파일 읽기에 실패
기존 파일이 있으면 파일의 처음 위치로 이동해서 해당 위치의 내용을 덮어쓸 수 있다.
"r+", "rb+", "r+b" 같이 사용
쓰기 강조 "w+"
읽기와 쓰기를 같이 사용할 때 쓰기를 더 강조하는 형식
기존 파일이 없으면 파일을 새로 생성
기존 파일이 있으면 기존 파일의 내용을 모두 지우고 시작
읽기와 이어 쓰기를 같이 사용하기 "a"
읽기와 이어 쓰기를 같이 사용하는 경우 확장을 더 강조하는 형식
기존 파일이 없으면 파일을 새로 생성
기존 파일이 있으면 파일의 내용을 지우지 않고 이어 쓰기
"r+" 와 달리 기존 데이터 위치로 이동 가능
쓰기를 사용하면 현재 위치와 상관없이 파일의 끝에 내용을 추가
"a+", "ab+", "a+b" 와 같이 사용
파일 닫기 함수 : fclose
함수 원형 : int fclose(FILE * stream);
함수 사용 형식 : fclose(파일 포인터)
fopen 함수를 사용하여 파일을 사용하다 사용이 끝나면 fclose 함수를 사용하여 파일을 닫는다.
파일을 열어 놓고 파일을 닫지 않으면 파일 내용이 지워지거나 파일을 사용할 수 없는 상태가 됨.
텍스트 파일에 데이터 읽고 쓰기
텍스트 파일에 문자열 저장하기 : fprintf함수(1)
fprintf 함수는 파일 포인터를 받아서 출력할 문자열을 파일에 저장
함수 원형 : int fprintf(FILE *stream, const char *format [, argument]....);
함수 사용 형식 : fprintf(파일 포인터, 파일에 입력할 문자 형식, 출력할 값들, ....)
fprintf(p, "Hellow\n");
FILE *p = fopen("test.txt", "wt");
if(NULL != p){
fprintf(p, "Hello\n");
fclose(p);
}
텍스트 파일에 문자열 저장하기 : fprintf함수(2)
fprintf 함수는 변수 값을 문자열로 파일에 출력 가능
표준 입출력 함수에서 제공하는 형식 지정 키워드를 사용 가능
short int data = 0x0412;
fprintf(p , "%x\n", data);
fprintf 함수는 호출될 때마다 자신이 파일에 저장한 문자열의 개수만큼 파일 포인터를 이동
(파일의 현재 사용 상태를 가리키는 정보 중에서 파일 내부 데이터를 읽거나 쓰는 위치가 문자열의 개수만큼 이동)
연속적으로 fprintf 함수를 호출하면 문자열이 차례대로 파일에 저장됨
short int data =0x0412;
fprintf(p, "Hello\n");
fprintf(p, "%x\n", data);
텍스트 파일에서 문자열 읽기 : fscanf 함수
fscanf 함수는 덱스트 파일에서 문자열을 얻기 위해 사용
함수 원형 : int fscanf(FILE *stream, const char *format [, argument ].....);
함수 사용 형식 : fscanf(파일 포인터, 파일에서 데이터를 입력 받을 형식, 입력 받을 변수 목록)
int data;
fscnaf(p, "%d", &data);
#include <stdio.h>
int main (void){
int num1, num2, num3;
FILE *p = fopen("test.txt","rt");
if(NULL != p){
fscanf(p, "%d %d %d", &num1, &num2, &num3);
printf("%d %d %d \n", num1, num2, num3);
fclose(p);
}
}
#include <stdio.h>
int main (void){
int num;
FILE *p = fopen("test.txt","rt");
if(NULL != p){
while( EOF != fscanf(p, "%d", &num) ) {
printf("%d \n", num);
}
fclose(p);
}
}
함수의 포인터 -> function data
프로세스 메모리 영역에 저장되는 명령
C언어로 작성한 소스코드가 기계어로 번역하면 실행 파일이 된다.
각 명령문은 메모리에 저장되어 있어 주소를 갖고 있다.
함수 포인터
특정 함수를 구성하는 시작 명령의 위치를 가리키는 포인터
함수 포인터를 사용하면 해당하는 함수를 호출하여 실행 가능
int Sum (int a, int b) {
int result = 0;
result = a + b; 호출 int result = Sum(2, 3);
return result;
}
∑ //Sum 함수의 첫 번째 명령문 주소를 의미함 &을 적지 않아도 같게 처리된다.
함수의 주소 값으로 함수 실행하기
함수 포인터는 함수 원형을 사용해서 포인터 선언
원형을 알지 못하면 함수를 호출할 시 스택 프레임 구성 불가
int (*p)(int, int); //Sum 함수를 가리킬 수 있는 함수 포인터를 선언한다.
p = &Sum //Sum 함수의 주소를 p 에 저장함
int result (*p)(2,3); //int result = Sum(2,3);과 같으므로 result 에 5가 저장
원형이 같은 함수들을 묶기
함수의 포인터를 사용하여 비슷한 함수를 반복문으로 호출하기
#include <stdio.h>
int Sum (int a, int b) {
return a + b;
}
int Sub (int a, int b) {
return a - b;
}
int Mul (int a, int b) {
return a * b;
}
int Div (int a, int b) {
return a / b;
}
void main () {
int (*p[4])(int, int) = ( &Sum, & Sub, &Mul, & Div), i;
char op_table[4] = {'+' , '-', '*', '/');
for(i = 0; i <4; i++) {
printf("%d %c %d = %d \n", 8, op_table[i], 2, (*p[4])(8,2) );
}
}
라이브러리를 만드는 라이브러리 프로그래머
특수한 기술을 구현할 수 있는 프로그래머들은 코드가 노출되면 안되기 때문에 코드를 라이브러리 형식의 파일로 제공
다른 사용자들도 사용할 수 있게 함수의 원형을 헤더 파일에 적어서 함께 제공
함수의 매개변수로 함수 포인터 사용하기
'TIPS' 카테고리의 다른 글
[TIPS 프로그래밍 강좌] 10차시 정리 (0) | 2017.02.08 |
---|---|
[TIPS 프로그래밍 강좌] 9차시 정리 (0) | 2017.02.06 |
[TIPS 프로그래밍 강좌] 7차시 정리 (0) | 2017.01.21 |
[TIPS 프로그래밍 강좌] 6차시 정리 (0) | 2017.01.19 |
[TIPS 프로그래밍 강좌] 6차시 정리 (0) | 2017.01.18 |
- Total
- Today
- Yesterday
- tipsoft
- tipssoft
- MFC
- 와이어샤크
- 팁스강좌
- 오일러 프로젝트 11번
- Tips
- CBrush
- 이미지게임
- 오일러 프로젝트 13
- 오일러 프로젝트 8번
- 오일러 프로젝트 16번
- 오일러
- tipsr강좌
- Omok
- 서버
- 패킷
- arp
- 오일러 프로젝트 14번
- 키보드 메시지 이벤트
- 헤더
- 오일러 프로젝트 12번
- 약수 500개
- 화투이미지맞추기
- 오일러 프로젝트 10본
- 비손실 압축
- TIPS강좌
- 허프만 알고리즘
- 2의 1000승
- 실행 압축
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |