반응형

출처 : https://www.yes24.com/Product/Goods/69750539

배열

연속적인 메모리 공간 할당 인덱스(index) 번호를 사용하여 쉽게 접근이 가능하기 때문에 반복 루프를 이용하여 여러가지 작업을 손쉽게 할 수 있다.

배열의 요소 메모리 주소
list[0] 기본주소=base
list[1] base + 1*sizeof(int)
list[2] base + 2*sizeof(int)
list[3] base + 3*sizeof(int)
list[4] base + 4*sizeof(int)
list[5] base + 5*sizeof(int)

int형은 4바이트이다.

 

구조체

타입이 다른 데이터를 묶는 방법

아래의 코드는 구조체와 배열을 이용한 다항식 덧셈 프로그램이다. (8x^3 + 7x + 1) + (10x^3 + 3x^2 + 1)

#include <stdio.h>
#include <stdlib.h>

#define MAX_TERMS 101
typedef struct {
	float coef; // 계수
	int expon; // 지수
} polynomial;
polynomial terms[MAX_TERMS] = { { 8,3 },{ 7,1 },{ 1,0 },{ 10,3 },{ 3,2 },{ 1,0 } }; 
//(8x^3 + 7x + 1) + (10x^3 + 3x^2 + 1)
int avail = 6;

// 두개의 정수를 비교
char compare(int a, int b)
{
	if (a>b) return '>';
	else if (a == b) return '=';
	else return '<';
}

// 새로운 항을 다항식에 추가한다.
void attach(float coef, int expon)
{
	if (avail>MAX_TERMS) {
		fprintf(stderr, "항의 개수가 너무 많음\n");
		exit(1);
	}
	terms[avail].coef = coef;
	terms[avail].expon = expon;
	avail++;
}

// C = A + B
void poly_add2(int As, int Ae, int Bs, int Be, int *Cs,
	int *Ce)
{
	float tempcoef;
	*Cs = avail;
	while (As <= Ae && Bs <= Be)
		switch (compare(terms[As].expon, terms[Bs].expon)) {
		case '>': 	// A의 차수 > B의 차수
			attach(terms[As].coef, terms[As].expon);
			As++;			break;
		case '=': 	// A의 차수 == B의 차수
			tempcoef = terms[As].coef + terms[Bs].coef;
			if (tempcoef)
				attach(tempcoef, terms[As].expon);
			As++; Bs++;		break;
		case '<': 	// A의 차수 < B의 차수
			attach(terms[Bs].coef, terms[Bs].expon);
			Bs++;			break;
		}
	// A의 나머지 항들을 이동함
	for (; As <= Ae; As++)
		attach(terms[As].coef, terms[As].expon);
	// B의 나머지 항들을 이동함
	for (; Bs <= Be; Bs++)
		attach(terms[Bs].coef, terms[Bs].expon);
	*Ce = avail - 1;
}
void print_poly(int s, int e)
{
	for (int i = s; i < e; i++)
		printf("%3.1fx^%d + ", terms[i].coef, terms[i].expon);
	printf("%3.1fx^%d\n", terms[e].coef, terms[e].expon);
}
//
int main(void)
{
	int As = 0, Ae = 2, Bs = 3, Be = 5, Cs, Ce; // start, end 1번 식 시작 끝, 2번식 시작 끝..
	poly_add2(As, Ae, Bs, Be, &Cs, &Ce);
	print_poly(As, Ae);
	print_poly(Bs, Be);
	printf(“-----------------------------------------------------------------------------\n”);
	print_poly(Cs, Ce);
	return 0;
}

실행결과

8.0x^3 + 7.0x^1 + 1.0x^0

10.0x^3 + 3.0x^2 + 1.0x^0

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

18.0x^3 + 3.0x^2 + 7.0x^1 + 2.0x^0

 

포인터

다른 변수의 주소를 가지고 있는 변수, 포인터 변수는 대개 정확한 숫자보다 그냥 화살표로 그려진다.

& 연산자 - 주소 연산자

* 연산자 - 간접참조 연산자 (역참조 연산자라고도 한다) 포인터가 가르키는 곳의 연산자

int a; // 정수형 변수
p = &a // 변수의 주소를 포인터에 저장
*p = 200; // a에 200 저장

 

포인터를 사용하기 전에는 반드시 널 포인터인지를 검사하여야 한다.

if( p== NULL )
{
	fprintf(stderr, "오류: 포인터가 아무 것도 카르키지 않습니다.");
	return;
}

 

함수 매개변수로 포인터 사용하기

#include <stdio.h>

void swap(int *px, int *py)
{
	int tmp;
	tmp = *px;
	*px = *py;
	*py = tmp;
}

int main(void)
{
	int a = 1, b = 2;
	printf("swap을 호출하기 전: a=%d, b=%d\n", a, b);
	swap(&a, &b);
	printf("swap을 호출한 다음: a=%d, b=%d\n", a, b);
	return 0;
}

실행결과

swap을 호출하기 전: a=1, b=2

swap을 호출한 다음: a=2, b=1

 

배열과 포인터

#include <stdio.h>
#define SIZE 6

void get_integers(int list[])
{
	printf("6개의 정수를 입력하시오: ");
	for (int i = 0; i < SIZE; ++i) {
		scanf("%d", &list[i]);
	}
}

int cal_sum(int list[])
{
	int sum = 0;
	for (int i = 0; i < SIZE; ++i) {
		sum += *(list + i); // list + i의 주소에 해당 되는 값을 sum에 저장
	}
	return sum;
}

int main(void)
{
	int list[SIZE];
	get_integers(list);
	printf("합 = %d \n", cal_sum(list));
	return 0;
}

실행결과

6개의 정수를 입력하시오: 1 2 3 4 5 6

합 = 21

 

동적 메모리 할당

동적 메모리가 할당되는 공간을 히프(heap)라고 한다. 히프는 운영체제가 사용되지 않는 메모리 공간을 모아 놓은 곳이다.

int *p;
p = (int *)malloc(sizeof(int)); // 1. 동적 메모리 할당
*p = 1000;			// 2. 동적 메모리 사용
free(p);			// 3. 동적 메모리 반납

1. malloc() 함수는 size 바이트 만큼의 메모리 블록을 할당한다. sizeof 키워드는 변수나 타입의 크기를 숫자로 반환한다. 크기의 단위는 바이트가 된다. sizeof(int)는 int형의 크기를 반환한다. malloc()은 동적 메모리 블럭의 시작주소를 반환한다. 반환되는 주소의 타입은 void *이므로 이를 적절한 포인터로 형변환시켜야 한다. 메모리 확보가 불가능하면 NULL을 함수의 반환값으로 반환한다.

2. 동적 메모리는 포인터로만 사용할 수 있다. *p는 p가 가르키는 장소이다. *p=1000; 문장을 실행하면 p가 가리키는 장소에 1000이 저장된다.

3. free() 함수는 할당된 메모리 블록을 운영체제에게 반환한다. 여기서 주의할 점은 malloc() 함수가 반환했던 포인터 값을 잊어버리면 안 된다는 것이다. 포인터값을 잊어버리면 동적 메모리를 반환할 수 없다. malloc()은 시스템의 메모리가 부족해서 요구된 메모리를 할당할 수 없으면 NULL을 반환한다. 따라서 malloc()의 반환갑은 항상 NULL인지 검사하여야 한다. 정수 10개를 저장할 수 있는 메모리를 동적으로 할당해보자.

// MALLOC.C: malloc을 이용하여 정수 10를 저장할 수 있는 동적 메모리를 
// 할당하고 free를 이용하여 메모리를 반납한다. 
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>

#define SIZE 10

int main(void)
{
	int *p;

	p = (int *)malloc(SIZE * sizeof(int));
	if (p == NULL) {
		fprintf(stderr, "메모리가 부족해서 할당할 수 없습니다.\n");
		exit(1);
	}

	for (int i = 0; i<SIZE; i++)
		p[i] = i;

	for (int i = 0; i<SIZE; i++)
		printf("%d ", p[i]);

	free(p);
	return 0;
}

실행결과

0 1 2 3 4 5 6 7 8 9

 

구조체와 포인터

구조체의 멤버에 접근하는 편리한 표기법 "->" ps가 구조체를 가리키는 포인터라고 할 때, (*ps).i 보다 ps->i라고 쓰는 것이 더 편리하다. 동적으로 생성된 구조체는 포인터를 통해서만 접근할 수 있다. 아래 코드에서는 malloc() 함수를 이용하여 student 구조체를 동적으로 생성한다.

include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct  studentTag {
	char name[10]; 		// 문자배열로 된 이름
	int age;	  	// 나이를 나타내는 정수값
	double gpa;	 	// 평균평점을 나타내는 실수값
} student;

int main(void)
{
	student *p;

	p = (student *)malloc(sizeof(student));
	if (p == NULL) {
		fprintf(stderr, "메모리가 부족해서 할당할 수 없습니다.\n");
		exit(1);
	}
	// (*s).name이라고도 할수 있지만 s->name이 더 편리하다.
	strcpy(p->name, "Park");	// 포인터가 아닐 경우 strcpy(s1.name, "kim");
	p->age = 20; 			//   		     s1.age = 20;

	free(s);
	return 0;
}

관심이 있으신 분들에게 유용한 정보였길 바라며

다음은 3장 퀴즈와 연습문제 해설을 가져오도록 하겠습니다.

반응형

+ Recent posts