[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까지의 출력결과는?
  1. 0x0039FCE8 + 16byte == 0x0039 FCF8
  2. *array == array[0] == &array[0][0] == 0x0039FCE8
  3. &array[1][0] == 0x0039FCF8

  4. array[0][0]+3 == 4
  5. array[0][2] == 3
  6. array[1][3] == 8


  • 메모리적인 관점

    • 0x0039… 는 컴퓨터 메모리 어딘가의 ‘주소’
    int value = 10;
      
    &value; // 0x0055.. 처럼 메모리 어딘가에 4byte 만큼 할당 된 것.
    value	// 그 주소에 해당하는 공간에 10이라는 값이 들어있는 것.
    

memoryAccessAboutArray



  • 이차원 포인터

image-20210801140834982



  • 메모리의 구체적인 주소

image-20210801140917301



  • 이차원 포인터의 사용
#include <stdio.h>

void main() {
	int num = 10;
	int* ptr = &num;
	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]);

image-20210802141540429



  • 문자열

    • 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에 할당되고, 그 주소가 포인터에 반환

    image-20210802154751748


  1. 선언과 동시에 초기화가 되느냐??
char str[15] = "캐릭터 배열";		// 가능!
char *pstr = "문자열 상수";			// 가능!


  1. 선언 이후에 초기화가 되느냐??
// char형 배열
char str[10] = "캐릭터 배열";
str = "수정된 배열";				// 불가!
str[0] = 's';					// 요소 하나하나 초기화 해야 함

// 문자열 상수
char *pstr = "문자열 상수";
pstr = "String_Const";			// 가능!


  1. 선언 이후에 수정이 되느냐??
// char형 배열
char str[10] = "charactor";
printf("%c", str[0])		// 접근도 가능!
str[0] = 'k';				// 수정도 가능!

/*  결과 : "kharactor"  */


// 문자열 상수
char *pstr = "stringConst";
printf("%c", pstr[0])		// 접근은 가능!
pstr[0] = 'x'  				// 수정은 불가!

/*  결과 : "error" */


  1. 문자열을 입력해서 넣을 수 있느냐?
// 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’ 널문자를 포함하고 있다.

image-20210809153306231

  • 이 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;

}


image-20201201141611603


구조체 선언

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;
}

image-20210809180835623


구조체 포인터

  • 멤버변수 접근할 때 . 을 썼었는데, 포인터에서는 ‘->’ 를 쓴다!!
// 내가 정의한 자료형!!
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영역에서 생기는 일

image-20201201142817970


  • 반드시 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);
}






© 2020.07. by Sanggoe

Powered by Sanggoe