[C] C언어 스터디 7주차
Review
Quiz!
- 포인터와 배열 관련하여 주소 개념을 잘 이해하고 있는지 확인할 수 있는 문제
#include <stdio.h>
int main(void) {
int array[2][4]={
{1, 2, 3, 4},
{5, 6, 7, 8}
};
/*1*/ printf("%#p\n" , array ); // 0x0039FCE8
/*2*/ printf("%#p\n" , array + 1 ); // 0x0039FCF8
/*3*/ printf("%#p\n" , * array ); // 0x0039FCE8
/*4*/ printf("%#p\n" , array[1] ); // 0x0039FCF8 // &array[1][0]
/*5*/ printf("%d\n" , array[0][0] + 3 ); // 4
/*6*/ printf("%d\n" , *( array[0] + 2 )); // 3
/*7*/ printf("%d\n", *(*(array + 1) + 3 )); // 8
return 0;
}
// 다차원 배열에서 * 라는 연산자, & 라는 연산자, [] 라는 접근 방법
// * 가 붙으면 [] 하나가 붙는다! 라고 이해를 했었음.
// & 가 붙으면 [] 하나가 없어진다. *가 없어진다.
// &, *, [] 이게 어떻게 유기적으로 다르게 표현 가능한지.
array[2][4] 2차원 배열에서
&array[0] == array
&array[0][0] == *array
&array[0] == array
array == array
- 위 프로그램에서 1 의 출력 결과가 0x0039FCE8 이었다. 2부터 7까지의 출력결과는?
- 0x0039FCE8 + 16byte == 0x0039 FCF8
- *array == array[0] == &array[0][0] == 0x0039FCE8
&array[1][0] == 0x0039FCF8
- array[0][0]+3 == 4
- array[0][2] == 3
- array[1][3] == 8
메모리적인 관점
- 0x0039… 는 컴퓨터 메모리 어딘가의 ‘주소’
int value = 10; &value; // 0x0055.. 처럼 메모리 어딘가에 4byte 만큼 할당 된 것. value // 그 주소에 해당하는 공간에 10이라는 값이 들어있는 것.
- 이차원 포인터
- 메모리의 구체적인 주소
- 이차원 포인터의 사용
#include <stdio.h>
void main() {
int num = 10;
int* ptr = #
int** ptr2 = &ptr;
printf("%d == %d == %d \n", num, *ptr, **ptr2);
printf("%p == %p == %p \n", &num, ptr, *ptr2);
printf("%p == %p \n", &ptr, ptr2);
*ptr = 20;
printf("%d\n", num);
**ptr2 = 30;
printf("%d\n", num);
}
- 이차원 포인터와 이차원 배열
int twoArr[2][2] = { {1,2}, {3,4} };
int** ptrptr = twoArr; // == &twoArr == twoArr[0] == &twoArr[0] == &twoArr[0][0]
printf("twoArr \t\t= %p\n", twoArr);
printf("&twoArr \t= %p\n", &twoArr);
printf("twoArr[0] \t= %p\n", twoArr[0]);
printf("&twoArr[0] \t= %p\n", &twoAr[0]);
printf("&twoArr[0][0] \t= %p\n", &twoArr[0][0]);
문자열
- char형 배열을 의미하기도 하고
- 문자열 상수를 의미하기도 한다.
// 선언과 동시에 초기화 하는 방법 char str[10] = "Hello!"; char *constStr = "문자열상수"; // 선언 후 초기화 하는 방법 char str[10]; // str = "Hello!"; // Error! str[0] = 'H'; str[1] = 'e'; str[2] = 'l'; str[3] = 'l'; str[4] = 'o'; str[5] = '!'; str[6] = '\0'; char *constStr; constStr = "문자열상수";
입출력
#include <stdio.h> void main() { char str[20]; scanf("%s", str); // hello printf("%s\n", str); // hello\0 }
배열 형식 / 문자열 상수 형식의 문자열의 차이?
- 배열 형식은 말 그대로 char형 배열
- 문자열 상수는 변경할 수 없는 ‘상수’가 Read Only Memory에 할당되고, 그 주소가 포인터에 반환
- 선언과 동시에 초기화가 되느냐??
char str[15] = "캐릭터 배열"; // 가능!
char *pstr = "문자열 상수"; // 가능!
- 선언 이후에 초기화가 되느냐??
// char형 배열
char str[10] = "캐릭터 배열";
str = "수정된 배열"; // 불가!
str[0] = 's'; // 요소 하나하나 초기화 해야 함
// 문자열 상수
char *pstr = "문자열 상수";
pstr = "String_Const"; // 가능!
- 선언 이후에 수정이 되느냐??
// char형 배열
char str[10] = "charactor";
printf("%c", str[0]) // 접근도 가능!
str[0] = 'k'; // 수정도 가능!
/* 결과 : "kharactor" */
// 문자열 상수
char *pstr = "stringConst";
printf("%c", pstr[0]) // 접근은 가능!
pstr[0] = 'x' // 수정은 불가!
/* 결과 : "error" */
- 문자열을 입력해서 넣을 수 있느냐?
// char형 배열
char str[10]; // 선언과 동시에 메모리 10byte만큼 할당 (길이 10) \0 포함!
scanf("%s", str) // 길이 10까지 입력 가능 (\0 문자포함) 가능!
// 문자열 상수
char *pstr = NULL; // 선언 시, char형 포인터 크기 4byte만큼 할당 (주소 대입 가능)
scanf("%s", pstr); // 가리키는 주소가 없습니다! 불가!
/*
=> 나중에 배울 malloc 동적 메모리 할당을 통해 해결 가능!
pstr = (char*) malloc (sizeof(char) * 10); // 반환된다.
heap 메모리에 char형*10 크기의 메모리가 할당되고, 그 첫번째 주소가 pstr에 대입된다.
scanf("%s", pstr);
*/
——————————–
문자열 함수
- **
헤더파일**에 미리 정의된 문자열 관련 함수가 많이 존재한다. - int strlen(char*) : 문자열 길이 구해 반환하는 함수
- void strcpy(char*, char*) : 문자열을 복사하는 함수
- void strcat(char*, char*) : 문자열을 이어 붙이는 함수
- int strcmp(char*, char*) : 문자열이 같은지 비교하는 함수
- int strstr() : 문자열 속에 문자열이 존재하는지 찾는 함수
- void strtok() : 문자열을 token으로 분리하는 함수
strlen()
- int strlen(char*)
- 문자열의 길이를 반환하는 함수
- ‘\0’ 널문자를 기준으로 문자열의 끝을 판단한다.
- 반환 타입 int형, 매개변수 char*형 (주소)
#include <stdio.h>
#include <string.h>
void main() {
char* str1 = "hello";
char str2[10] = "hello";
char str3[10];
str3[0] = 'h';
str3[1] = 'e';
..'\0'
int len;
len = strlen(str1); // &str1[0]
printf("str1의 길이 : %d\n", len);
len = strlen(str2);
printf("str2의 길이 : %d\n", len);
}
- 길이는 ‘h’, ‘e’, ‘l,’ ‘l’, ‘o’ 5가 나온다.
- 물론 실제로 메모리상에서는 아래와 같이 ‘\0’ 널문자를 포함하고 있다.
- 이 strlen() 함수는 ‘\0’을 기준으로 문자열의 끝을 판단한다.
- 문자열에서는 널문자 ‘\0’를 반드시 항상 고려해야 한다!
strcpy()
- void strcpy(char* result, char* source)
- 문자열을 복사하는 함수
- source를 result에 복사한다.
- 이 함수 역시 ‘\0’를 기준으로 문자열의 끝을 판단
- 반환값은 없다. call by reference!
- 주의할 점, 메모리의 크기를 반드시 고려해주어야 한다!
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
void main() {
char source[10] = "Hello";
char result[10];
char *str;
strcpy(result, source);
strcpy(str, source); // error!
printf("%s\n", result);
}
strcat()
- void strcat(char* result, char* source)
- 문자열을 이어 붙이는 함수
- source를 result의 뒤에 이어 붙인다.
- 이 함수 역시 ‘\0’를 기준으로 문자열의 끝을 판단
- 반환값은 없다. call by reference!
- 주의할 점, 메모리의 크기를 반드시 고려해주어야 한다!
#include <stdio.h>
#include <string.h>
void main() {
char result[20] = "Hello";
char source[10] = "my friend";
strcat(result, source);
printf("%s\n", result);
}
strcmp()
- int strcmp(char* str1, char* str2)
- 문자열이 같은지 비교하는 함수
- 두 문자열을 앞에서부터 비교하며 문자의 아스키코드 값을 비교
- 반환 타입 int형, 매개변수 char*형 (주소)
- -1 : ASCII 코드 기준으로 문자열2(str2)가 더 클 때
- 0 : ASCII 코드 기준으로 두 문자열이 같을 때
- 1 : ASCII 코드 기준으로 문자열1(str1)이 클 때
- hallo, hello 비교
- h를 먼저 비교한다. → 같다!
- 다음 a와 e를 비교한다. → 아스키코드로 하면 e가 더 크다!
- 뒤에 있는 hello가 더 크므로 -1을 반환
#include <stdio.h>
#include <string.h>
void main() {
char str1[10] = "Hello";
char* str2 = "Hello";
int result;
result = strcmp(str1, str2);
if (result == 0) {
printf("%s와 %s는 같다.\n", str1, str2);
} else {
printf("%s와 %s는 다르다.\n", str1, str2);
}
}
#include <stdio.h>
#include <string.h>
void main() {
// ASCII 코드로 a는 97, b는 98, c는 99
printf("%d\n", strcmp("aa", "aa")); // 0: aa와 aa는 같으므로 0
printf("%d\n", strcmp("ab", "aa")); // 1: ab와 aa 중에서 ab가 크므로 1
printf("%d\n", strcmp("ab", "ac")); // -1: ab와 ac 중에서 ac가 크므로 -1
}
실습 및 과제로 해봅시다!
int myStrlen(char* s)
- 길이 구하는 함수
#include <stdio.h>
int myStrlen(char *s);
void main() {
char *str = "hello, 경종!!";
printf("길이는 %d\n", myStrlen(str));
}
int myStrlen(char *s) {
int count = 0;
/*
for (int i=0; s[i] != '\0'; i++) {
count++;
}
*/
while (*(s++) != '\0') {
count++;
}
return count;
}
void myStrcpy(char* to, char* from)
- 복사 하는 함수
#include <stdio.h>
void myStrcpy(char* to, char* from);
void main() {
char to[21];
char* from = "hello, kyeong jong!!";
myStrcpy(to, from);
printf("%s\n", to);
}
void myStrcpy(char* to, char* from) {
// int i=0;
while (*(from) != '\0') {
*(to++) = *(from++);
// to[i] = from[i];
// i++;
}
*to = '\0';
}
void myStrcat(char* to, char* from)
- 이어붙이는 함수
#include <stdio.h>
void myStrcat(char* to, char* from);
void main() {
char to[21] = "I'm ";
char* from = "kyeong jong!";
myStrcat(to, from);
printf("%s\n", to);
}
void myStrcat(char* to, char* from) {
while(*(to++) != '\0');
to--;
while (*(from) != '\0') {
*(to++) = *(from++);
// to[i] = from[i];
// i++;
}
*to = '\0';
}
int myStrcmp(char* str1, char* str2) // 과제!
- 같은지 비교하는 함수
#include <stdio.h>
#include <ctype.h>
int myStrCmp(char* from, char* to) {
int i;
// i=0 ~ from의 길이(strlen(from) 또는 from[i] != NULL 또는 *from != NULL)까지 반복문 돌려서
// from의 i번째와 to의 i번째가 같으면 넘어가고 다르면 false!!!
// 반복문이 끝까지 잘 수행되면 true!!
}
void main() {
char* from = "test string";
char* to = "test string";
if (myStrCmp(from, to)) {
print("same string\n");
} else {
print("different string\n");
}
}
my_toUpper(), my_toLower() // 과제
- ASCII code 응용
- 문자열의 모든 문자를 대문자로 / 소문자로 만들어 저장하는 함수
// my_toUpper 소문자면 대문자로 만드는 함수
// 문자 하나하나 비교해서, if 해당 문자가 'a' <= 문자 <= 'z' => +32
비밀번호 확인 프로그램 // 과제
- 비밀번호를 입력할 때 ‘*’ 문자로 대신 출력
- backspace를 누르면 ‘*’ 문자 삭제 및 입력값도 삭제
- 엔터키를 누르면 비밀번호 입력 완료
- 비밀번호 일치 확인
문자열에 존재하는 모든 숫자를 더한 결과를 반환하는 함수를 구현하시오.
- 연속으로 나온 숫자도 1의 자리로 각각 더함
#include <stdio.h>
int onlyAddNumeric(char* s) {
// 구현하시오
}
void main() {
// 하나하나 비교할 때 str에 한글을 쓰면 연산 도중 Error가 발생할 수 있음! 주의 s[i]
char* str = "Today is 2021-08-12"; // 인터넷에 아스키코드표 검색, if '0' <= 문자가 <= '9'
int num = onlyAddNumeric(str);
printf("%d\n", num); // 결과는 16
}
// ASCII CODE로 '0'은 48, '9'는 57
문자열의 가운데 글자를 반환하는 함수를 구현하시오.
- 문자 개수가 홀수이면 가운데, 짝수이면 가운데 두 글자를 반환
- 홀수, 짝수를 판별할 때 ‘\0’는 포함하지 않음
#include <stdio.h>
#include <string.h>
char* getCenter(char* s) {
int len = strlen(s);
char* str = (char*)malloc(sizeof(char) * 3);
// char str2[10]; 으로 선언 시, 함수 바깥에서 접근하면 쓰레기값 출력.
// 함수 내 지역변수로 선언이 되기때문에 함수 종료시에 str2배열 메모리 영역이 사라진다.
// stack 메모리는 임시 공간!! 함수 호출시 할당, 종료시 반환. 지역변수..
// heap 메모리는 프로그래머가 할당 할 수 있는 영역. 메모리를 할당해서 사용하기 위해 동적으로 할당
if (len % 2) { // 홀수인 경우. 7/2 = 3 (나머지를 버리는 연산)
strncpy(str, s + len/2, 1);
str[1] = 0; // NULL 문자 대입 필수
}
else { // 짝수인 경우. 6/2 = 3. 2~3을 반환하기 위해 -1 해줌
strncpy(str, s + len/2 - 1, 2);
str[2] = 0; // NULL 문자 대입 필수
}
// printf("%s\n", str2);
return str;
}
void main() {
char* str = "Center"; // 짝수 strlen(str) 6
char* str2 = "Centers"; // 홀수 strlen(str) 7
char* center = getCenter(str);
char* center2 = getCenter(str2);
printf("%s\n", center); // nt // index : 2-3
printf("%s\n", center2); // t // index : 3
}
——————————–
구조체
구조체의 이해
- 변수 : 지정된 자료형의 데이터를 담는 상자
- 배열 : 동일한 종류의 데이터를 하나로 묶어 사용 int [], char [], double [], ….
- 구조체 : 서로 다른 종류의 데이터를 하나로 묶어 사용
- 내가 원하는 자료형을 가져다가 만드는 것. 즉, 내가 만든 자료형!
// 맛보기!
struct 이름 {
char name[10]; // 10 byte
int stunum; // 4 byte
}
int main() {
struct 이름 s1, s2, s3; // 14byte 메모리
s1.name; // 배열의 첫 주소
s2.name[0]; // 배열 0번째 인덱스의 값
&s3.name[0]; // 배열의 첫 주소
s1.stunum = 10;
printf("%d\n", s1.stunum);
}
// int형의 경우, '개념적'으로는 이렇게 정의된 자료형인 것
typedef struct int {
4byte int; // 4byte
} int;
// 내가 만든 사용자 정의 자료형
typedef struct student {
char name[10]; // 10byte
int stunum; // 4byte
} STD;
int a, b, c
STD a, b, c
// int, char, STD
int : 4byte / int 넣을 수 있는 자료형.
STD : 14byte / char 10개, int 1개 넣을 수 있는 자료형.
구조체 정의
- 내가 만든 상자 모양 - 사용자 정의 자료형
- typedef (자료형 정의)
typedef struct bookInfo { // typedef를 써서 자료형 이름을 만들어줘도 되고
int bookNum;
char *title;
char author[10];
} Book;
struct bookIF { // 이렇게 안써도 된다. 다만 자료형 풀네임으로 써주어야 한다.
int bookNum;
char *title;
char author[10];
}
int main() {
struct bookInfo book1, book2; // 또는 Book book1, book2;
struct bookIF b1, b2;
}
구조체 선언
int main() {
struct bookInfo book1, book2;
Book book1, book2;
}
구조체 사용
- 멤버변수 접근 : . (도트 연산자)으로 접근
- ~에 속하는. 내장된.. 그런 의미!
typedef struct bookInfo {
int bookNum;
char *title;
char author[10];
} Book;
(struct bookInfo) book1.bookNum = 10; // 내장하고 있는 변수에 접근
book1.bookTitle // error! undeclare 정의되지 않은 변수입니다..
1. scanf("%s", book1.author); // 둘다
2. scanf("%s", &book1.author[0]); // 돼요
#include <stdio.h>
typedef struct myInfo {
int age;
char name[15];
} INFO;
void main() {
INFO human1;
struct myInfo human2;
human1.age = 23;
strcpy(human1.name, "kyeong jong");
human2.age = 25;
strcpy(human2.name, "sang min");
}
함수 매개변수 인자로 쓰이는 경우
// 사용자 정의 변수 모음 타입 이라는거를 기억하면 이해하기 쉬움~!
void func1(int num, char str[10]);
void func2(struct bookInfo b1, Book b2);
// struct bookInfo : 자료형 풀네임 또는 Book : 정의된 자료형 이름
함수 반환형으로 쓰이는 경우
int func1(int num, char str[10]);
struct bookInfo func2(struct bookInfo b1, Book b2);
Book func2(struct bookInfo b1, Book b2){
struct bookInfo newBook;
newBook.bookNum = 1335;
newBook.title = "Where is my book?";
strcpy(newBook.author, "unKnown");
return newBook;
}
선언된 구조체가 여러 개 일 때??
// 내가 선언한 자료형!!
typedef struct bookInfo {
int bookNum;
char *title;
char author[10];
} Book;
typedef struct dot {
int x;
int y;
} DOT;
typedef struct student {
int stdNum;
char *name;
} STD;
// int, char, double ... + BOOK, DOT, STD;
// 이 프로그램 내에서 어디서든지 사용할 수 있는 자료형을 내가 만들어 준 것!!
STD getStudent() {
STD s1 = ~~~~
...
return s1;
}
DOT getLocation() {
DOT d1 = ~~~~
...
return d1
}
BOOK getBookInformation() {
BOOK b1[10] = ~~~;
STD s1
...
return b1;
}
// C언어에서 함수의 리턴값은 하나!!
구조체 배열
- 배열과 다를게 없다.
- 배열 : 같은 자료형 타입으로 여러개 묶여있는거
- 구조체 배열 : 같은 자료형(구조체를 자료형으로 가지는) 배열
구조체 배열 선언
int arr[10];
int* getArrFunction(int arr[], int *arr2) {
...
}
// 배열하고 다를게 없다 똑같은 '배열' 이다!!!
BOOK* getBookInformation(BOOK* b1, struct bookInfo* b2, BOOK b3[10]) {
BOOK b1[10] = ~~~; // BOOK을 Type으로 가지는 10개 짜리 배열
// b1이 의미하는 바는??
&b1[0] == &b1;
...
return b1;
}
구조체 포인터
- 멤버변수 접근할 때 . 을 썼었는데, 포인터에서는 ‘->’ 를 쓴다!!
// 내가 정의한 자료형!!
typedef struct bookInfo {
int bookNum;
char *title;
char author[10];
} Book;
// 구조체 배열의 이름이 구조체 포인터!
Book *bp; // 선언 포인터 사이즈는 4바이트!! (보통. 윈도우에서.. 32bit에서...)
int main() {
Book bArr[10] = ~~~;
bp = bArr; // bArr[0]
...
// 포인터 형식 접근
bp->bookNum // ->로 접근
(bp+1)->bookNum; // 인덱스를 더해서 해당 포인터 값에 ->로 접근
arr[2][4]
arr + 1
// 배열 형식 접근
bArr[0].bookNum;
bArr[1].bookNum;
bp[0].bookNum;
bp[1].bookNum;
*ptr / ptr[i]
// 배열, 포인터 하고 완전 똑같음!!
}
——————————–
동적 메모리 할당
동적 메모리 할당의 이해
함수 원형
- (void *) malloc (size_t size)
- (반환 타입) malloc (할당 크기); 형태로 사용한다.
- 메모리만 할당될 뿐, 변수에는 쓰레기값이 들어있다. 초기화 X
#define SIZE 10
int** m = (int**)malloc(sizeof(int*));
// 문자열 상수 - 수정 못해
char *str = "hello!";
// 어딘가에 Read only memory로 할당이 되고, 첫 번째 주소가 str에 반환된다
// malloc을 쓰면
char *myStr = (char*) malloc (sizeof(char)*10);
// heap 메모리 어딘가에 접근 및 수정 가능한 memory로 할당이 되고, 첫 번째 주소가 myStr에 반환된다
- size는 명시적으로 해주기 위함. 사실 크기를 직접 입력해도 상관 없다.
- sizeof(int) == sizeof(int*) == sizeof(char)*4 == sizeof(1*4) == 4
malloc 함수의 사용
- 포인터 변수를 선언해, 함수를 호출한다.
- malloc 함수를 호출하면, heap 메모리 어딘가에 해당 크기가 할당이 되고, 그 첫 번째 주소가 반환이 된다.
#include <stdio.h>
void main() {
char* str; // 그냥 NULL 상태.
char* str2; // 그냥 NULL 상태.
str = (char*) malloc (sizeof(char)*20);
// str : 20byte가 메모리에 할당되고, 해당 메모리의 첫 번째 주소를 가리키고 있는 상태
// str2 : 아무것도 가리키고 있지 않는 상태
scanf("%s", str);
scanf("%s", str2); // Error
}
calloc 함수의 사용
- (void *) calloc (size_t n, size_t size)
- (반환 타입) malloc (할당 크기); 형태로 사용한다.
- 0으로 초기화해서 할당하는 함수
realloc 함수의 사용
- (void *) realloc (void *p, size_t size)
- (반환 타입) malloc (할당받은 주소, 할당 크기); 형태로 사용한다.
- 이미 할당받은 주소에 다시 할당받기 (사이즈 줄이거나 키울 때)
메모리 할당의 종류
- 정적 메모리할당 (코드 치고 컴파일하면 할당)
- 동적 메모리할당
- 10만 메모리 할당
- 반드시 free 해주어야 함!!
- 궁극적으로 동적 메모리 할당하는 짓 - 메모리낭비를 줄이기 위해서. 메모리를 효율적으로 쓰기 위해서.
- 배열, 포인터
- 배열의 이름 == 주소
- 포인터변수 == 주소가 담기는 변수
- 배열의 이름 == 포인터 변수
- 포인터 변수에 malloc 한 배열?? == 배열하고 똑같다
- memory allocation을 수행하면 Heap영역에서 생기는 일
- 반드시 free!
- free 하지 않으면 생기는 일은?
- 메모리의 낭비가 발생한다!!
- free 하지 않으면 생기는 일은?
어려운 개념이라..
- 앞선 내용들 기초가 다져진 뒤에 공부하는 것을 추천합니다.
- 같이 해보며 저렇구나만 이해합시다.
#include <stdio.h>
#define SIZE 1000
#define TEN 10
typedef struct bookInfo {
int bookNum;
char *title; // 1000개 할당!
char author[10];
} Book;
void main() {
int* ap; // 1000개의 int형 배열 만들고싶다!
Book *b1;
char* main_title; // 1000개의 char형 배열 만들고싶다!
// (저장할 변수의 타입으로 타입캐스팅) malloc (할당 받고싶은 메모리 크기(byte))
ap = (int*) malloc (sizeof(int)*SIZE); // int형 1000
main_title = (char*) malloc (sizeof(char)*SIZE); // char형 1000
b1 = (Book*) malloc (sizeof(Book)*TEN);
b1[0].title = (char*) malloc (sizeof(char)*SIZE); // char형 1000
...
ap = (int*) realloc (ap, sizeof(int)*TEN); // int형 10
main_title = (char*) realloc (main_title, sizeof(char)*TEN); // char형 10
b1.title = (char*)realloc(b1.title, sizeof(char)*TEN); // char형 10
free(ap); // 메모리 할당 해제
free(main_title);
free(b1[0].title);
free(b1);
ap = NULL;
}
구조체 배열 만들어서 할당하기?
- malloc, alloc, realloc 같이 써볼까요?
/* 프로그램 조건
STD 라는 이름으로 typedef 구조체 정의
STD 내용 : age, name(*형)
STD getStudent(); malloc을 응용 STD 변수를 만들어 반환
*/
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define NUM 5
#define SIZE 10
typedef struct student {
int age; // 4
char* name; // 4
} STD;
// malloc으로 STD 할당받아 age, name 값 입력받기
STD* getStudents() {
int i;
STD* students = NULL; // 아무것도 가리키고 있지 않다!
// students 를 NUM만큼 malloc으로 받으라!!
students = (STD*)malloc(sizeof(STD) * NUM); // (1)
for (i = 0; i < NUM; i++) {
// 1. 배열 접근 방식
students[i].name = (char*)malloc(sizeof(char)*SIZE); // (2) name을 SIZE만큼할당
// 2. 포인터 접근 방식
(students+i)->name = (char*)malloc(sizeof(char) * SIZE); // (2) name을 SIZE만큼할당
printf("age : ");
scanf("%d", &students[i].age);
printf("name : ");
scanf("%s", students[i].name);
}
return students;
}
void showStudents(STD* students) {
// 학생의 (나이, 이름) 을 모두 출력!
for (int i = 0; i < NUM; i++) {
printf("age는 %d살이고, name은 %s입니다.\n", (students + i)->age, students[i].name);
}
}
int main() {
STD* students; // STD 구조체 포인터. 배열의 첫 주소를 담을 변수
students = getStudents(); // complete!
showStudents(students);
}