VSCODE 환경 C개발환경


Visual Studio Code에서 C개발 환경 설정 방법입니다.



1.MinGW 다운로드


아래 URL에서 다운가능합니다.


https://sourceforge.net/projects/mingw-w64/files/latest/download


2. 환경변수 설정


아래 경로와 같이 설치된 경로 \bin폴더까지 복사를 한 후


D:\Program Files (x86)\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin


Path변수에 추가를 해줍니다.




3. gcc컴파일러 확인


커맨드창 혹은 VSCODE 콘솔창에서 


gcc --version 명령을 통해 컴파일러 버전을 확인합니다.



4. 컴파일 및 테스트


컴파일 확인 결과 exe가 정상적으로 생성되는걸 확인할 수 있습니다.




'언어 > C' 카테고리의 다른 글

[C] 계좌 관리 프로그램  (2) 2017.01.10
[C] 파일 입·출력  (0) 2017.01.05
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

계좌 관리 프로그램

 

 지금까지 공부한 내용들을 바탕으로 계좌 관리 프로그램을 작성해 봤습니다. 계좌를 생성하는 기능과 입금, 출금하는 기능 계좌 전체를 조회하는 기능이 있습니다. 파일 입출력을 이용해서 "data.txt"라는 텍스트 파일에 있는 계좌정보를 가져오기도하고, 계좌를 생성한 뒤에 입금, 출금 한 내용을 "data.txt"파일에 저장할 수 있도록 했습니다. "bank.h"헤더파일과 "bank.c","main.c" 세 파일로 분할 컴파일 했습니다. "bank.h"헤더파일에는 구조체 정의와 각 함수정의 및 헤더파일들을 인클루드했고, "bank.c"에서는 각 함수들의 기능 구현을 했습니다. 마지막으로 "main.c"는 "bank.h"헤더파일을 인클루드하고 "bank.c"의 함수를 호출해서 사용하도록 작성 했습니다.


- bank.h

----------------------------------------------------------------------------------------

#define NAME_LEN 20 // define은 단순매크로로 값을 정해 편하게 사용할 수 있습니다. 

// 아래 헤더파일을 bank.h에 인클루드한 이유는 main.c와 bank.c에서 사용하기 위해서 입니다.

#include <stdio.h> 

#include <stdlib.h>

#include <string.h>

#pragma warning(disable:4996)


typedef struct bank{ // 계좌정보를 저장할 구조체 선언

char *name[NAME_LEN]; // 예금주[최대20자리]

int id;                         // 계좌번호

int money;                   // 잔액

struct bank *next;

}bank;


bank *head, *tail; // 노드의 처음과 끝

void Init_account(FILE *fp); // 노드의 처음과 끝에 메모리 할당하고, 파일에서 입력을 받도록 하는 함수

void Make_account(FILE *fp); // 계좌를 생성하는 함수

void Deposit(FILE *fp); // 입금 함수

void WithDraw(FILE *fp); // 출금 함수

void WriteAccount(FILE *fp); // 계좌의 정보를 저장하는 함수

void Account_inquire(void); // 계좌를 조회하는 함수

void ReadAccount(int id, char *name, int money); // 텍스트 파일에서 입력을 받는 함수

----------------------------------------------------------------------------------------


- bank.c

----------------------------------------------------------------------------------------


#include "bank.h"


void Init_account(FILE *fp)

{

int id;

char name[NAME_LEN];

int money;

head = (bank *)malloc(sizeof(bank));

tail = (bank *)malloc(sizeof(bank));

head->next = tail;

tail->next = tail;


while (fscanf(fp, "%d %s %d", &id, name, &money) == 3){ // 정수형, 문자형, 정수형 3개일 때만 입력을 받음

ReadAccount(id, name, money);

}

}


void ReadAccount(int id, char *name, int money)

{

bank *t;

t = (bank *)malloc(sizeof(bank));

t->id = id;

strcpy(t->name, name);

t->money = money;


t->next = head->next; // 다음 노드를 가리킴

head->next = t; // 노드의 처음을 가리킴

}


void Make_account(FILE *fp)

{

int id;

char name[NAME_LEN];

int money;

bank *t;

t = (bank *)malloc(sizeof(bank));


printf("\n*********계좌 생성*********\n");

printf("계좌번호 : "); scanf("%d", &id);

printf("예 금 주 : "); scanf("%s", name);

printf("입 금 액 : "); scanf("%d", &money);


t->id = id;

strcpy(t->name, name);

t->money = money;


t->next = head->next;

head->next = t;


WriteAccount(fp); // 저장하는 함수로 파일 포인터를 넘겨줌

}


void Deposit(FILE *fp)

{

int id;

int money;

bank *t;

printf("계좌번호 : "); scanf("%d", &id);

printf("입 금 액 : "); scanf("%d", &money);


for (t = head->next; t != tail; t = t->next)

{

if (t->id == id)

{

t->money += money; // 잔액에 입금할 금액을 더해서

WriteAccount(fp); // 저장

return;

}

}

printf("없는 계좌번호입니다.\n");

}


void WithDraw(FILE *fp)

{

int id;

int money;

bank *t;

printf("계좌번호 : "); scanf("%d", &id);

printf("출 금 액 : "); scanf("%d", &money);


for (t = head->next; t != tail; t = t->next)

{

if (t->id == id)

{

if (t->money<money) // 출금액이 잔액보다 클 경우

{

printf("출금액이 잔액을 초과할 수 없습니다.\n");

return;

}

else{

t->money -= money; // 잔액에서 출금액을 빼서

}

WriteAccount(fp); // 저장

return;

}

}

printf("없는 계좌번호입니다.\n");

}

void Account_inquire(void)

{

bank *t;

for (t = head->next; t != tail; t = t->next)

{

printf("\n*********잔액 조회*********\n");

printf("계좌번호 : %d\n", t->id);

printf("예 금 주 : %s님\n", t->name);

printf("잔    액 : %d원\n\n", t->money);

}

}


void WriteAccount(FILE *fp)

{

bank *t;

rewind(fp); // 파일 읽는 포인터 지점을 맨 첨으로 돌리는 함수

for (t = head->next; t != tail; t = t->next)

{

fprintf(fp, "%d %s %d\n", t->id, t->name, t->money);

}

}

----------------------------------------------------------------------------------------


- main.c

----------------------------------------------------------------------------------------

#include "bank.h"

int main()
{
int input;
FILE *fp;
fp = fopen("data.txt", "r+"); // 파일모드가 r+일 경우  읽고쓰기를 동시에 수행 합니다.
Init_account(fp);

do{
printf("계좌 생성&관리 프로그램입니다. 원하시는 번호를 입력하세요.\n");
printf("*********************************************\n");
printf("1)계좌 생성 2)계좌 조회 3)입금 4)출금 5)종료\n");
printf("*********************************************\n");
printf("입력 >");
scanf("%d", &input);

switch (input){
case 1:
Make_account(fp);
break;
case 2:
Account_inquire();
break;
case 3:
Deposit(fp);
break;
case 4:
WithDraw(fp);
break;
case 5:
input = 0;
free(head); // 종료하면서 메모리 반환
free(tail);
break;
default:
printf("잘못 입력하셨습니다. \n");
return main();
}
}
while (input != 0);
}

----------------------------------------------------------------------------------------


 위 코드의 실행 결과는 다음과 같습니다. 우선 "data.txt"파일에 초기값으로 아래 그림과 같이 입력 하고 저장한뒤에 프로그램을 실행했습니다.


 계좌 하나를 추가로 생성하고, 새로만든 계좌와 기존의 계좌 각각 입금, 출금을 수행했습니다. 


 계좌를 조회하고 종료하는 그림입니다. 새로만든 계좌와 기존의 계좌 모두 정상적으로 출력됩니다. "data.txt"파일에도 저장되었을까요?


 살짝 깨지기는 했지만 값이 정상적으로 저장된걸 확인 할 수 있습니다.




'언어 > C' 카테고리의 다른 글

VSCODE 환경 C개발 환경  (0) 2019.03.27
[C] 파일 입·출력  (0) 2017.01.05
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

파일 입·출력


 파일에 대한 개념은 잘 알고계실겁니다. 응용 프로그램 부터 시작해서 텍스트파일 엑셀파일 등 모든 파일이 파일에 속합니다. 지금까지 앞에서 공부했던 내용들만 가지고 프로그램을 짜보면 한번 실행하면 다시 또 처음부터 실행해야됩니다. 파일 입·출력을 이용하면 파일을 이용해서 입력을받거나, 프로그램에서 입력한 내용을 파일로 출력을 할 수 있습니다. 파일 입·출력은 <stdio.h>헤더파일을 인클루드 하면 사용할 수 있습니다.


 우선, 파일 입·출력 공부에 앞서 비쥬얼 스튜디오의 프로젝트 경로를 쉽게 확인할 수 있는 방법을 알려드리겠습니다. 파일의 입력, 출력을 하기위해서는 소스코드가 생성되는 프로젝트 경로를 알고 있어야합니다. 아래 그림처럼 프로젝트를 우클릭하고 "파일 탐색기에서 폴더 열기"를 누르면 소스코드가 있는 프로젝트의 경로가 열립니다.



파일 입력

 파일 입력은 파일 열기, 작업, 파일 닫기 세 단계로 구성됩니다. 파일 열기는 fopen()함수, 파일에서 값을 불러올때는 fscanf()함수 파일을 닫을때는 fclose()함수를 사용합니다. 파일을 열고나서 닫지 않으면, 다른 곳에서 해당파일에 접근할 수 가 없으므로 꼭 사용한 후에는 닫아줘야 합니다. 파일 입·출력에서는 파일 포인터를 사용합니다. 파일 포인터는 타입이 파일인 포인터 라고 생각하시면 됩니다.


- fopen()함수

 파일을 열 때 사용하는 함수입니다. 열 파일이 존재하지 않거나, 실패할 경우 NULL값을 반환합니다.

----------------------------------------------------------------------------------------

fopen(파일이름, 파일모드); // 파일모드 r(read)=읽기 w(write)=쓰기(파일 출력에 사용)

FILE *fp; // 파일포인터 선언

fp=fopen("test.txt","r"); // test.txt 파일을 읽기

----------------------------------------------------------------------------------------


- fscanf()함수

 fscanf()함수는 파일의 내용을 읽어올 때 사용하는 함수로, 파일 포인터를 인자값으로 사용한다는 점 외에는 scanf()함수와 유사합니다.

----------------------------------------------------------------------------------------

fscanf(파일 포인터, 포맷 문자열, 값1, 값2 ...);

FILE *fp; // 파일포인터 선언

int i;
fscanf(fp,"%d",&i);

----------------------------------------------------------------------------------------


- fclose()함수

 fclose()함수는 파일을 닫는 함수로, 열려있는 파일 포인터를 인수로 넘겨주면 파일을 닫는 역할을 합니다. 

----------------------------------------------------------------------------------------

fclose(파일 포인터);

FILE *fp; // 파일포인터 선언

fclose(fp);

----------------------------------------------------------------------------------------


 위 세 함수를 이용해서 "data.txt"라는 파일에 정수를 입력해서, "data.txt"파일을 입력 받고 정수를 출력하는 코드를 작성해 봤습니다. 이 때 "data.txt"처럼 사용 할 파일은 소스파일과 같은 경로에 있어야 합니다. 아래 그림은 "data.txt"입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


int main()

{

int a,b; // 파일에서 읽어올 때 fscanf에 사용할 변수a와 반복문에 사용할 변수 b 선언

int *data; // 동적메모리에 사용할 정수형 포인터 선언

FILE *fp; // 파일포인터 fp 선언

fp = fopen("data.txt","r"); // "data.txt"파일 열기


if (fp != NULL) // 파일이 정상적으로 열렸을 때 if문실행

{

fscanf(fp,"%d",&a); // "data.txt"파일의 첫번째 값을 입력받아서

data = (int *)malloc(sizeof(int)*a); // 첫번째 값만큼 동적으로 정수형 배열을 만듭니다.

for (b = 0; b < a; b++) // 배열의 크기만큼 값을 입력 받음

{

fscanf(fp, "%d", &data[b]); 

}

fclose(fp); // 입력을 받은뒤에 파일닫기


for (b = 0; b < a; b++) // 입력받은 배열을 출력

{

printf("data[%d] : %d \n", b, data[b]);

}

free(data); // 메모리 반환

} //close if()


else{

printf("파일 입력받기 실패 \n"); 

}

}

----------------------------------------------------------------------------------------

 위 코드를 실행한 결과입니다. "data.txt"의 처음 값은 배열의 크기가 되고, 나머지 값들은 순차적으로 배열에 저장해서 출력했습니다.


파일 출력

 파일 출력은 두 가지로 나뉩니다. 기존 파일을 사용해서 출력하는 방법과 새로운 파일을 만들어서 출력하는 방법이 있습니다. 두 방법은 기존의 파일을 이용하는 점과 새로만든다는 점만 다를뿐 구현방법은 동일합니다. 파일 출력은 파일 입력과 동일하게 fopen()함수를 사용합니다. fscanf()함수와 반대로 fprintf()함수를 이용해 파일에 출력합니다.


- fopen()함수

 fopen()함수의 파일모드에는 r(read),w(write)외에도 a(append)가있습니다.

----------------------------------------------------------------------------------------

fopen()함수의 파일모드

- w = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 내용을 덮어쓰기

- a = 해당 파일이 없으면 파일을 생성, 해당 파일이 있으면 파일의 끝부터 내용 추가

----------------------------------------------------------------------------------------


- fprintf()함수

 fprintf()함수는 파일에 문자열을 출력하는 함수로 파일 포인터를 인자값으로 사용한다는 점 외에는 printf()함수와 유사합니다.

----------------------------------------------------------------------------------------
FILE *fp;
fprintf(fp,"문자열 : %s \n",text);
----------------------------------------------------------------------------------------

 문자열이 아닌 자료형 등의 데이터를 읽고 쓰려면 어떻게 해야될까요? 이때는 2진수(binary)값을 직접 읽고 씁니다. fopen()함수의 기존 파일모드에 b를 붙여서 사용합니다. 바이너리 값을 읽고 쓸때에는 fread()함수와 fwrite()함수를 사용합니다.

----------------------------------------------------------------------------------------
fopen(“data.txt”, “rb”);
fopen(“data.txt”, “wb”);

size_t fread( void *ptr, size_t size, size_t nitems, FILE *stream); 
(파일에서 읽은 값을 저장할 포인터, 자료형의 크기, 자료형의 개수, 파일 포인터)
size_t fwrite( void *ptr, size_t size, size_t nitems, FILE *stream);
사용 방법은 동일하지만, 변수 포인터에 들어있는 값을 파일에 쓴다는점이 다릅니다.
----------------------------------------------------------------------------------------

아래 코드는 바이너리 값으로 구조체를 파일로 저장하고 읽어오는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


struct Node{

int a;

double b;

};


int main()

{

struct Node *print;

FILE *fp;

fp = fopen("data.txt", "wb"); // 바이너리값으로 저장


print = (struct Node*)malloc(sizeof(struct Node));

print->a = 1;

print->b = 3.14;

fwrite((void*)print, sizeof(struct Node), 1, fp);

fclose(fp); // 파일 닫기

  free(print); // 메모리반환

}

----------------------------------------------------------------------------------------

 위 코드를 실행하면 도스창에는 아무런 문자열도 출력되지 않습니다.

 "data.txt"파일을 열어보면 아래 그림과 같이 1과 3.14가 아닌 깨진 문자들이 출력이 됩니다. 잘못 저장된걸까요?


 위에 저장된 "data.tx"t파일을 읽어와서 출력하는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


struct Node{

int a;

double b;

};


int main()

{

struct Node *open;

FILE *fp;

fp = fopen("data.txt", "rb"); // 바이너리값으로 불러오기


open = (struct Node*)malloc(sizeof(struct Node));

fread((void*)open, sizeof(struct Node), 1, fp);


printf("open->a = %d \n", open->a);

printf("open->b = %.2lf \n", open->b);


fclose(fp); // 파일닫기

free(open); // 메모리반환


}

----------------------------------------------------------------------------------------

 위 코드의 실행결과입니다. 파일을 출력했을때의 값이 정상적으로 출력되는걸 확인할 수 있습니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

VSCODE 환경 C개발 환경  (0) 2019.03.27
[C] 계좌 관리 프로그램  (2) 2017.01.10
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27

자기 참조 구조체


 자기 참조 구조체는 자신과 동일한 구조체를 가리킬 수 있는 포인터 변수를 필드 변수로 가지는 구조체입니다. 형태는 다음과 같습니다.

----------------------------------------------------------------------------------------

struct Node

{

int a;

struct Node* b; // 자신의 구조체를 가리키는 포인터 변수

};

----------------------------------------------------------------------------------------


연결리스트

 연결리스트는 컴퓨터 관련 공부나 자격증 공부를할 때 많이 들어보셨을 단어입니다. 연결리스트는 구조체와 포인터를 이용해 유동적으로 데이터를 저장할 수 있는 자료구조로 자기 참조 구조체를 연결해 사용합니다. 아래 그림과 같이 a의 주소만 알고있다면 b와 c에 접근이 가능한 구조입니다.

 struct Node *head;와 같이 구조체를 정의했을 때 위 그림의 a,b,c노드에 접근하는 방법은 아래 표와 같습니다

a.n

 head → n

b.n

 head → next → n

c.n

 head → next → next → n

 

 위의 그림을 봤을때 각 노드는 다음 노드의 주소를 가리킵니다. 마지막 노드는 어떤 주소를 가리킬까요? 마지막 노드는 NULL값을 저장합니다. 이 NULL값은 더이상 연결된 노드가 없음을 의미합니다.


 아래 코드는 정수를 입력받아 연결리스트를 구성해서 출력하고 메모리를 반환한뒤에 종료하는 코드입니다. 반복문에서는 p = p->next; 와같은 문장을 이용해 참조를 이동할 수 있습니다.
----------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#pragma warning(disable:4996)

struct Node{
int n;
struct Node *next;
};

void showMenu(); // 반복문안에서 입력을 받기위한 문자열을 출력하는 함수
void printNodes(struct Node* p); // 입력받은 정수를 출력하기 위한 함수
void freeNodes(struct Node* p); // 사용이 끝난 노드의 메모리를 반환하는 함수

int main(){
int flag = 1; // 반복문을 실행하기 위한 변수로 1로 초기화 하고 0이 될때 반복문이 종료됩니다.
int input; // 입력받을 정수
struct Node *head; // 노드의 처음
struct Node *last; // 노드의 끝
struct Node *node; // 추가될 노드의 주소를 임시로 저장할 포인터 변수

head = NULL; // 추가된 노드가 없기때문에 head와 last를 NULL로 초기화
last = NULL;

while (flag){
showMenu();
scanf("%d", &input);

if (input == 0) // 0을입력하면 종료
{
flag = 0;
}
else{
node = (struct Node*)malloc(sizeof(struct Node)); // 구조체 역시 sizeof연산자를 이용할 수 있습니다. 구조체를 동적할당
node->n = input; // 생성된 Node 구조체에 값을 설정합니다.
node->next = NULL;

if (head == NULL) // 연결 리스트가 비어있을 경우, head에 생성된 node 의 주소를 저장
{
head = node;
}
else // 연결 리스트가 비어있지 않을 경우, 마지막 노드의 next에 생성된 node 의 주소를 저장합니다.
  {
last->next = node;
}
last = node; // 연결 리스트에 추가된 node 의 주소를 last 에 저장합니다.
}
}
  // 반복문이 종료되면 printNodes함수와 freeNodes함수를 실행합니다.
printNodes(head); 
freeNodes(head);
}

void showMenu(){
printf("저장할 정수를 입력하세요. \n 종료 0 >");
}

void printNodes(struct Node* p)
{
while (p != NULL){  // 마지막 노드가 아닌 경우
printf("%d\n", p->n); // 노드를출력하고,
p = p->next; // 다음 노드를 가리킵니다.
}
}
void freeNodes(struct Node* p){
struct Node *temp;
while (p != NULL){ // 마지막 노드가 아닌 경우
temp = p; // temp에 p를 저장해서
p = p->next; 
free(temp); // 반환합니다.
}
}
----------------------------------------------------------------------------------------

 실행 결과는 아래와 같습니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 계좌 관리 프로그램  (2) 2017.01.10
[C] 파일 입·출력  (0) 2017.01.05
[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27
[C] 구조체  (2) 2016.12.26

 2016년이 지나고 2017년 새해가 밝았습니다. 2017년에는 2016년보다 좀 더 열심히 공부할 생각입니다. 


동적 메모리

 메모리에는 정적 메모리와 동적메모리가 있습니다. 정적 메모리는 여태 공부하면서 사용했던 배열이나, 프로그램 실행 전에 선언했던 변수등이 사용하는 공간을 뜻합니다. 반대로 동적 메모리는 프로그램 실행 시점에서 메모리 공간을 설정하고 사용할 수 있는 메모리 공간으로 프로그램이 실행되는 동안에 필요한 변수나 배열 등을 동적으로 할당합니다. 

 얼만큼 사용할지 모르는 공간을 정적 메모리로 할당하면, 메모리를 낭비하게 될 수 있는데, 동적 메모리를 사용하면 필요한 만큼만 할당하기 때문에 메모리 낭비를 줄일 수 있습니다. 

 동적메모리는 이름이 없고, 메모리 주소를 포인터 변수에 저장해서 사용하며,  타입에 따라 형변환을 해서 사용합니다. 동적 메모리는 표준 라이브러리 stldib.h를 인클루드하면 사용할 수 있습니다. 동적 메모리를 할당하면 반환을 해줘야합니다. 반환을 하지 않으면 메모리 누수가 발생합니다. malloc함수를 사용해 할당하고 free함수를 사용해 반환합니다.

 동적메모리 사용은 다음과 같습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>


int main()

{

int *value; // 정수형 포인터 변수 선언

value = (int*)malloc(4); // 4바이트 크기의 동적 메모리 할당

*value = 100;


printf("valuie : %d\n", *value);

free(value); // 메모리 반환

}

----------------------------------------------------------------------------------------


 컴파일러에 따라서 int 타입의 크기가 2바이트로 할당하기도하고 4바이트로 할당하기도 합니다. 이때 sizeof 연산자를 사용하면 타입의 크기를 반환하게 되서 컴파일러에 맞게 사용할 수 있습니다. 다른타입 역시 마찬가지로 sizeof연산자를 이용해서 사용할 수 있습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>


int main()

{

int *a;

float *b;

double *c;

char *d;


a = (int*)malloc(sizeof(int));

b = (float*)malloc(sizeof(float));

c = (double*)malloc(sizeof(double));

d = (char*)malloc(sizeof(char));


*a = 100;

*b = 3.14;

*c = 5.25;

*d = 'a';


printf("a : %d\n", *a);

printf("b : %.2f\n", *b);

printf("c : %.2f\n", *c);

printf("d : %c\n", *d);


free(a);

free(b);

free(c);

free(d);

}

----------------------------------------------------------------------------------------


 배열 또한 동적으로 메모리를 할당할 수 있습니다. 아래 코드와 같이 할당하고 사용할 수 있습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <stdlib.h>

#pragma warning(disable:4996)


int main()

{

int count, i, input;

int *array;

printf("배열의 크기를 입력하세요 : ");

scanf("%d", &count);

array = (int*)malloc(sizeof(int)*count); // 메모리공간을 정수형크기 * 입력한 수 만큼 할당


for (i = 0; i < count; i++)

{

printf("%d 번째 수 : ",i);

scanf("%d", &input);

*(array + i) = input; // 입력받은 값을 배열의 0번째부터 저장

}


printf("---------------------------\n"); // 구분선


for (i = 0; i < count; i++)

{

printf("*(array+%d) : %d\n", i, *(array + i)); // 배열의 0번째부터 출력

}


free(array); // 메모리 반환


}

----------------------------------------------------------------------------------------


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 파일 입·출력  (0) 2017.01.05
[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 공용체  (0) 2016.12.27
[C] 구조체  (2) 2016.12.26
[C] 배열과 포인터  (3) 2016.12.25

공용체


 공용체는 하나의 공간을 동으로 사하는 자료형입니다. 공용체 안에 여러 자료형이 있을때, 가장 큰 자료형 하나 만큼만 메모리를 점유하기때문에, 메모리를 절약할 수 있다는 큰 장점이 있습니다.

 공용체의 사용은 struct 대신 union을 사용한다는 점을 제외하면 구조체와 거의 유사합니다.

----------------------------------------------------------------------------------------

// 공용체 정의

union test{

int age;

char *name;

char *hobby;

}; 


// 공용체 필드에 접근

union [공용체 이름] [공용체 변수이름];

union test p1;

[구조체 변수이름].[구조체 필드이름];

p1.name;

----------------------------------------------------------------------------------------


 공용체는 하나의 공간을 사용하기 때문에 모든 필드의 시작주소가 같습니다. 아래코드는 test라는 공용체를 만들어서 a,b,c 필드의 주소를 출력하는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>


union test{

int a;

char *b;

double c;

};


int main()

{

union test a;


printf("int형 주소    : %d \nchar형 주소   : %d \ndouble형 주소 : %d \n", &a.a, &a.b, &a.c);

return 0;

}

----------------------------------------------------------------------------------------

이처럼 전부 같은 주소가 출력됩니다.


 아래 코드는 구조체를 활용해 성적 입력 및 조회하는 코드를 작성해 봤습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <string.h>

#pragma warning(disable:4996)


typedef struct{ // 이렇게 구조체를 선언하면 사용할 때 struct [구조체 이름] 대신 구조체 이름만 가지고 사용할 수 있습니다. 

char name[20];

int math;

int com;

}student;


void insert(student arr[], char *name, int math, int com, int count); // 성적입력 처리 함수

int search(student arr[], char *name, int count); // 이름을 통해 조회하는 함수

void output(student arr[], int count); // 전체 입력된 값을 출력하는 함수


int main(){

student arr[20];

char name[20];

int count = 0;

int select,math, com,i;


while (1){

printf("선택) 1.성적 추가 2.성적 조회 3.전체 조회 4.종료 : ");

scanf("%d", &select);


if (select == 1){

printf("이름, 수학 성적, 컴퓨터 성적 : ");

scanf("%s %d %d", name, &math, &com);

insert(arr, name, math, com, count);

count++;

}

else if (select == 2){

printf("이름 : ");

scanf("%s", name, &math, &com);

i = search(arr, name, count);

if (i != -1)

printf("%s %d %d \n", arr[i].name, arr[i].math, arr[i].com);

else

printf("%s 찾지못함 \n", name);

}

else if (select == 3){

output(arr, count);

}

else if (select == 4){

printf("종료합니다. \n");

break;

}

else{

printf("선택 오류 \n");

}

}// close while()


return 0;

}


void insert(student arr[], char *name, int math, int com, int count){

strcpy(arr[count].name, name);

arr[count].math = math;

arr[count].com = com;

}


int search(student arr[], char *name, int count){

int i;

for (i = 0; i < count; i++){

if (!strcmp(arr[i].name, name)) // 문자열 비교함수

return i;

}

return -1;

}


void output(student arr[], int count){

int i;

for (i = 0; i < count; i++)

{

printf("%s %d %d \n", arr[i].name, arr[i].math, arr[i].com);

}

}

----------------------------------------------------------------------------------------

실행 결과는 아래와 같습니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 자기 참조 구조체와 연결리스트  (2) 2017.01.04
[C] 동적 메모리  (0) 2017.01.03
[C] 구조체  (2) 2016.12.26
[C] 배열과 포인터  (3) 2016.12.25
[C] 포인터  (0) 2016.12.23

 자료형에는 기본 자료형과 유도자료형이 있습니다. 기본 자료형은 초반에 공부했던 정수형, 부동소수형, 문자형등이 있고, 유도 자료형은 기본 자료형을 응용해서 보다 복잡한 자료 구현하는 자료형으로 앞에서 공부한 배열, 포인터 그리고 구조체와 공용체가 있습니다.


구조체

 구조체란 여러 종류의 변수를 하나로 묶어서 사용하는 데이터 타입으로 사용자가 직접 정의하는 사용자 정의 타입중 하나입니다. 앞에서 공부했던 함수처럼 메인함수 위쪽에 정의해야 메인함수 등 코드의 아래쪽에서 사용할 수 있습니다. 구조체의 정의와 사용은 아래와 같습니다.

----------------------------------------------------------------------------------------

// 구조체 정의

struct test{

int age;

char *name;

char *hobby;

}; // 세미콜론을 꼭 붙여줘야합니다.


// 구조체 필드에 접근

struct [구조체 이름] [구조체 변수이름];

struct test p1;

[구조체 변수이름].[구조체 필드이름];

p1.name;

----------------------------------------------------------------------------------------


 구조체 변수를  포인터로도 사용할 수 있습니다. 이때, 구조체 필드에 접근은 어떻게 표현할까요?

----------------------------------------------------------------------------------------

struct test{

int age;

char *name;

char *hobby;

};

struct test *p1;

(*p1).age; // 이렇게 표현이 가능하지만 

p1->age; // 이렇게 화살표로도 표현이 가능합니다.

----------------------------------------------------------------------------------------


 이름, 국어, 수학 성적을 입력받아 평균까지 출력하는 코드를 작성해 봤습니다. 사실 간단하게 작성할 수 있는 내용이지만, 구조체를 이용했습니다. 이름, 국어, 수학 성적을 입력을 받고 평균을 계산해서 구조체에 넘겨준뒤에, 구조체를 매개변수로 하는 함수를 이용해 출력을 했습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>

#include <string.h>

#pragma warning(disable:4996)


struct student{

char name[5];

int korean;

int math;

double average;

};


void out(struct student a); // 구조체를 매개변수로 하는 함수 정의


int main()

{

char input_name[10];

int input_korean;

int input_math;

struct student b;

printf("이름과 성적을 입력하세요.\n");

printf("이름 : ");

scanf("%s", input_name);

printf("국어 : ");

scanf("%d", &input_korean);

printf("수학 : ");

scanf("%d", &input_math);

printf("-----입력 완료-----\n");


strcpy(b.name ,input_name);

b.korean = input_korean;

b.math = input_math;

b.average = (double)(b.korean +b.math) / 2;


out(b); // 함수호출로 출력


return 0;

}


void out(struct student a) 구조체를 매개변수로 하는 함수 구현

{

printf("이름 : %s \n국어 : %d \n수학 : %d \n평균 : %.2lf\n", a.name, a.korean, a.math, a.average);

}

----------------------------------------------------------------------------------------


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 동적 메모리  (0) 2017.01.03
[C] 공용체  (0) 2016.12.27
[C] 배열과 포인터  (3) 2016.12.25
[C] 포인터  (0) 2016.12.23
[C] 배열  (0) 2016.12.23

배열(Array)과 포인터(Pointer)

 

 제목을 배열과 포인터라고 한 이유는, 배열을 이용해 포인터를 사용하고 포인터를 이용해 배열을 사용하기 때문입니다. 포인터는 주소를 가리키는 것인데, 배열은 메모리 일정공간에 연속으로 존재하기때문에, 배열을 이용해 포인터를 사용할 수 있습니다.

 배열의 주소는 어떻게 표현할까요? 변수의 주소처럼 &를 붙여 &arr[0]이렇게도 표현할 수 있지만, 배열의 이름 자체가 배열의 첫번째 원소의 주소입니다. 배열의 이름을 포인터 상수 라고도 하는데, 포인터 상수는 주소값의 변경이 불가능합니다.


 아래 코드는 정수형 변수와 배열의 주소 비교입니다. 

----------------------------------------------------------------------------------------

#include <stdio.h>


int main()

{

int a, b, c;

int d[3];

printf("a : %d, b : %d, c : %d \n",&a,&b,&c);

printf("d[0] : %d d[1] : %d d[2] : %d \n", &d[0], &d[1], &d[2]);

return 0;

}

----------------------------------------------------------------------------------------

 배열의주소는 int형이라 4바이트씩 즉 4씩 차이가나고, int형 변수 a,b,c는 규칙없이 각기 다른 주소에 저장되었습니다.

 

 이제 배열을 이용해 포인터를 사용해 보겠습니다. 아래 코드는 배열에 hello 라는 문자열을 넣고 포인터 변수를 선언해 주소를 가리킨뒤에 포인터를 출력해보는 코드입니다.

----------------------------------------------------------------------------------------

#include <stdio.h>


int main()

{

char text[6] = "hello"; // 널값을 포함한 문자열의길이 6바이트

char *pointer; // 포인터 변수 선언

pointer = text; 


printf("text : %s \n", text); // 배열주소의 값 출력

printf("pointer : %s \n", pointer); // 포인터가 가리키는 주소의 값 출력

printf("--------------- \n");

int i;

for (i = 0; i < 5; i++){

printf("%.1s \n",pointer+i); // 맨 앞글자만 출력

}

----------------------------------------------------------------------------------------

 아래 결과를 보면 포인터 변수 역시 배열의 주소를 가리켜서 같은 hello가 출력이 됩니다. 원소를 한글자씩 출력하기위해서 반복문안에 출력문을 포맷을 %.1s로 지정했는데, %s로 지정 하면 포인터가 가리키는 주소도 1씩 증가해서 hello, ello, llo, lo, o가 출력이됩니다.


포인터 변수는 사용자의 입력을 받을때의 변수로도 사용할 수도 있습니다. 

----------------------------------------------------------------------------------------

#include <stdio.h>

#pragma warning(disable:4996)


int main()

{

int input;

int *pointer;

pointer = &input;


printf("정수 입력 : ");

scanf("%d", pointer);

printf("입력된 정수 : %d \n", *pointer);

}

----------------------------------------------------------------------------------------


 마지막으로, 포인터 변수를 이용해서 문자열을 입력받아 대문자는 소문자로 소문자는 대문자로 바꾸는 코드를 작성해 봤습니다. 포인터 변수로 입력을 받고, 출력은 배열로 했습니다.

----------------------------------------------------------------------------------------

#include <stdio.h>
#pragma warning(disable:4996)

int main(){

char change[10];
char *input;
input = &change;

printf("영문을 입력하시면 대소문자가 서로 변환됩니다. 입력 : ");
scanf("%s", input);

while (*input){ 
if (*input >= 'A' && *input <= 'Z') // 대문자일 경우
{
*input = *input + 32;
}
else if (*input >= 'a' && *input <= 'z') // 소문자일 경우
{
*input = *input - 32;
}
input++;
}
printf("변환된 문자 : %s \n", change);
}

----------------------------------------------------------------------------------------

조건문에서 왜 +32, -32 연산을 하는지 이해가 안되시는분은 조건문 게시글 http://parkdream.tistory.com/11 을 참고하시면 됩니다. 

 *input+32, -32 대신 *input-'A'+'a' *input-'a'+'A'를 사용하셔도 됩니다.

결과는 아래와 같이 대소문자가 서로 바뀌어서 출력됩니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 공용체  (0) 2016.12.27
[C] 구조체  (2) 2016.12.26
[C] 포인터  (0) 2016.12.23
[C] 배열  (0) 2016.12.23
[C] 디버깅  (0) 2016.12.21

포인터(Pointer)


 C언어가 고급 언어이면서, 저급 언어로도 불리는 가장 큰 이유는 메모리를 직접 제어할 수 있는 포인터 때문입니다. 포인터는 주어진 메모리를 가리키는 것으로, 메모리 공간에 대한 이해가 필요합니다. 우선 메모리 공간에 대해 알아보겠습니다. 


- 메모리 공간

 메모리 공간은 순서대로 정렬되어있는 연속된 값으로, 메모리 주소당 1바이트의 크기를 가집니다. 메모리는 여러 의미가 있지만, C언어에서는 변수가 사용하는 공간으로, 변수를 선언하게되면 일정 메모리 공간을 점유하게됩니다. 


- 포인터

 포인터는 "자료형 *변수이름;" 과 같이사용하며, 주소를 사용하는 것과 메모리 주소로 사용하는것이 있습니다. 아래 코드를 보면, 포인터는 변수 a의주소를 가리키므로, pointer를 출력하면 a의 주소가 출력되고, *pointer를 출력하면 변수 a의값인 10이 출력됩니다.

----------------------------------------------------------------------------------------

#include <stdio.h>


int main()

{

int a=10;

int *pointer;

pointer = &a;

printf("a : %d \n", a);

printf("&a : %d \n", &a);


printf("pointer : %d \n", pointer);

printf("*pointer : %d \n", *pointer);


return 0;

}

------------------------------------------------------------------------------------------

 

- 포인터 주소값 조작

포인터의 주소값을 이용해서, 주소값을 조작할 수 있습니다. 다음과 같이 정수형, 문자형, 부동소수형 변수를 선언한뒤에 주소값을 1씩 증가시켰습니다. 결과값이 어떻게 출력될까요?

----------------------------------------------------------------------------------------

#include <stdio.h> 

int main()
{
int a=10;
char b='a';
double c=3.14;

int *ptr1;
char *ptr2;
double *ptr3;

ptr1 = &a;
ptr2 = &b;
ptr3 = &c;

printf("ptr1 : %d \nptr1+1 :%d \n", ptr1, ptr1 + 1);
printf("ptr2 : %d \nptr2+1 :%d \n", ptr2, ptr2 + 1);
printf("ptr3 : %d \nptr3+1 :%d \n", ptr3, ptr3 + 1);

}

----------------------------------------------------------------------------------------

 결과를 보면 주소가 int형은 4만큼, 문자형은 1만큼, 부동소수형은 8만큼 증가했죠? 메모리공간에 각각 4,1,8바이트의 크기를 가지기 때문에 주소를 1증가하면, 자료형의 크기만큼 증가합니다.

 자료형의 크기가 기억 나지 않는분들은 http://parkdream.tistory.com/4 글을  참고하시면 됩니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 구조체  (2) 2016.12.26
[C] 배열과 포인터  (3) 2016.12.25
[C] 배열  (0) 2016.12.23
[C] 디버깅  (0) 2016.12.21
[C] 매개변수 전달 방식  (0) 2016.12.20

배열(Array)


 배열은 변수들을 연속으로 선언해서 일괄적으로 사용하는 자료형입니다. 배열은 일차원 배열과 다차원 배열로 나뉘며, 앞에서 공부할 때 몇번 활용한 적이 있습니다. 배열 없이 정수형 변수 5개를 선언할 경우 int a,b,c,d,e; 처럼 일일이 직접 선언해야하는데 배열을 사용하면 int a[5]; 처럼 한번에 선언할 수 있습니다. 배열을 전달할 경우 참조 전달이 되기 때문에 *이나 &를 붙이지 않아도 됩니다. 


- 배열

 배열의 사용은 아래와 같습니다. 인덱스는 0부터 시작하며, 변수도 사용 가능합니다. 한가지 주의할 점은 배열은 한가지 자료형으로만 구성해야하며, 선언된 배열의 길이를 초과하는 인덱스를 사용하면 안됩니다.

----------------------------------------------------------------------------------------

타입 변수명[인덱스]

int a[5]; 

int b[];

int c=5; 

int d[c]; 

------------------------------------------------------------------------------------------

 배열에 값을 넣을 때, 초기화하면서 선언할수는 있지만, 선언한뒤에 값을 한번에 넣지는 못합니다.

------------------------------------------------------------------------------------------

int a[3]={1,2,3};   (가능)

int b[3];

b={1,2,3};          (불가능)

→ b[0]=1; b[1]=2; b[2]=3; (가능) b[3]=4: // 배열의 길이를 초과하므로 불가능

------------------------------------------------------------------------------------------




- 다차원 배열

 다차원 배열은 배열을 원소로 가지는 배열을 뜻합니다. 아래와 같이 사용하며 부분적으로 초기화가 가능합니다.

------------------------------------------------------------------------------------------

 int a[3][3]={1,2,3,4,5,6,7,8,9}; 
위와 같이 초기화 하는 경우 배열에는 아래 표와같이 값이 들어갑니다. 
int a[][3]={1,2,3,4,5,6,7,8,9}로 초기화할 경우, 자동으로 초기화된 값을 보고, int[3][3]과 같은 배열의 길이를 가집니다.

구분 

 첫번째

두번째 

 세번째

 a[1]

 a[2]

4

5

 a[3]

 ------------------------------------------------------------------------------------------

 
아래와 같이 부분적으로 초기화할 경우 값이 순서대로 들어가는 것이 아니라 빈자리에는 0이 채워집니다.

 ------------------------------------------------------------------------------------------

int a[3][3]={{1},{4,5},{7,8,9}};

구분 

1번째

2번째 

 3번째

a[1]

0

a[2]

4

5

a[3]

7

------------------------------------------------------------------------------------------

 
문자열은 정수와 다르게, 문자열의 끝에 \0(널문자)를 넣어줘야 합니다. \0를 넣는 이유는 문자열의 끝을 구분하기 위해서 입니다. 문자열은 부분적으로 초기화 할경우에 0대신 \0가 채워집니다.

------------------------------------------------------------------------------------------

char a[3][8] ={"red","skyblue","mint"}

구분 

1번째 

2번째 

3번째 

4번째 

5번째 

6번째 

7번째 

8번째 

a[1] 

r

\0 

\0 

\0 

\0 

\0 

a[2]

\0 

a[3] 

\0 

\0 

\0 

\0 

------------------------------------------------------------------------------------------


 배열을 이용해 16진수를 입력받아 10진수로 변환해주는 소스코드를 작성해 봤습니다.

------------------------------------------------------------------------------------------

#include <stdio.h>

#pragma warning(disable:4996)


int main()

{

char a[] = { '0','1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E' ,'F'}; //16진수 배열

char input[3]; // 입력을 받는 배열 

int i, j;

int num = 0;

printf("10진수로 변환할 16진수를 입력하세요 : ");

scanf("%s", input);

for (i = 0; input[i] != '\0'; i++) // 입력한 배열의 문자가 널문자가 아닐때까지 반복

for (j = 0; j < 16; j++) // 0~16까지 같은수를 찾을때까지 반복  

if (input[i] == a[j])

num = num * 16 + j;


printf("십진수 : %d \n", num);


return 0;


}

------------------------------------------------------------------------------------------

위의 코드를 실행하면 아래와 같은 결과가 출력됩니다. A1을 입력했을때, 'A'는 배열 a의 10번째 이므로 j가 10이되고 num=0*16+10이되서 10이되고, '1'은 배열a의 1번째이므로 다시 num=10*16+1이되서 161이 출력됩니다.


* 출처 : 한국기술교육대학교 온라인평생교육원 C 프로그래밍_2 

          스타일 C프로그래밍 저.김종훈,김종진 출.WellBook




'언어 > C' 카테고리의 다른 글

[C] 배열과 포인터  (3) 2016.12.25
[C] 포인터  (0) 2016.12.23
[C] 디버깅  (0) 2016.12.21
[C] 매개변수 전달 방식  (0) 2016.12.20
[C] 함수(2)  (0) 2016.12.20

+ Recent posts