자료구조

[자료구조] 배열 구조체 포인터

유일리 2022. 10. 18. 10:39

배열

같은 형의 변수를 여러 개 만드는 경우에 사용한다. 반복 코드 등에서 배열을 사용하면 효율적인 프로그래밍이 가능하다.

  • 배열의 응용 : 다항식

다항식의 일반적인 형태

다항식 표현 방법

모든 차수에 대한 계수값을 배열로 저장한다. 하나의 다항식을 하나의 배열로 표현한다.

#include <stdio.h>
#define MAX(a,b) (((a)>(b))?(a):(b))
#define MAX_DEGREE 101 // 다항식의 최대차수 + 1

typedef struct {
	int degree;
	float coef[MAX_DEGREE];
} polynomial;

polynomial a = { 5, {10, 0, 0, 0, 6, 3} };

// C = A+B 여기서 A와 B는 다항식이다. 구조체가 반환된다. 
polynomial poly_add1(polynomial A, polynomial B)
{
	polynomial C;				// 결과 다항식
	int Apos = 0, Bpos = 0, Cpos = 0;	// 배열 인덱스 변수
	int degree_a = A.degree;
	int degree_b = B.degree;
	C.degree = MAX(A.degree, B.degree); // 결과 다항식 차수
	while (Apos <= A.degree && Bpos <= B.degree) {
		if (degree_a > degree_b) { // A항 > B항
			C.coef[Cpos++] = A.coef[Apos++];
			degree_a--;
		}
		else if (degree_a == degree_b) { // A항 == B항
			C.coef[Cpos++] = A.coef[Apos++] + B.coef[Bpos++];
			degree_a--; degree_b--;
		}
		else {			// B항 > A항
			C.coef[Cpos++] = B.coef[Bpos++];
			degree_b--;
		}
	}
	return C;
}
void print_poly(polynomial p)
{
	for (int i = p.degree; i > 0; i--)
		printf("%3.1fx^%d + ", p.coef[p.degree - i], i);
	printf("%3.1f \n", p.coef[p.degree]);
}
// 주함수
int main()
{
	polynomial a = { 5,{ 3, 6, 0, 0, 0, 10 } };
	polynomial b = { 4,{ 7, 0, 5, 0, 1 } };
	polynomial c;
	print_poly(a);
	print_poly(b);
	c = poly_add1(a, b);
	printf("-----------------------------------------------------------------------------\n");
	print_poly(c);
	return 0;
}

  • 배열의 응용 : 희소행렬

희소행렬은 대부분의 항들이 0인 배열이다.

희소행렬 표현방법

2차원 배열을 이용하여 배열의 전체 요소를 저장하는 방법이다. 장점은 행렬의 연산들을 간단하게 구현할 수 있는 것이고, 단점은 대부분의 항들이 0인 희소 행렬의 경우 많은 메모리 공간을 낭비한다는 것이다.

#include <stdio.h>
#define ROWS 3
#define COLS 3
// 희소 행렬 덧셈 함수
void sparse_matrix_add1(int A[ROWS][COLS],
	int B[ROWS][COLS], int C[ROWS][COLS]) // C=A+B
{
	int r, c;
	for (r = 0; r < ROWS; r++)
		for (c = 0; c < COLS; c++)
			C[r][c] = A[r][c] + B[r][c];
}
main()
{
	int array1[ROWS][COLS] = { { 2,3,0 },
				{ 8,9,1 },
				{ 7,0,5 } };
	int array2[ROWS][COLS] = { { 1,0,0 },
				{ 1,0,0 },
				{ 1,0,0 } };
	int array3[ROWS][COLS];
	sparse_matrix_add1(array1, array2, array3);
}

구조체

타입이 다른 데이터를 하나로 묶는 방법이다.

배열은 타입이 같은 데이터들을 하나로 묶는 방법이다.

  • 구조체 사용의 예
//구조체 선언
struct studentTag {
	char name[10]; 	// 문자배열로 된 이름
	int age;	  	// 나이를 나타내는 정수값
	double gpa;	  // 평균평점을 나타내는 실수값
};

//구조체 변수 생성
struct studentTag s;
strcpy(s.name, "kim");
s.age = 20;
s.gpa = 4.3;
  • typedef 사용

C언어의 typedef 키워드는 이미 존재하는 타입에 새로운 이름을 붙일 때 사용한다.

구조체 변수를 선언하거나 사용할 때에는 매번 struct 키워드를 사용하여 구조체임을 명시해야 한다.

하지만 typedef 키워드를 사용하여 구조체에 새로운 이름을 선언하면 매번 struct 키워드를 사용하지 않아도 된다.

#include <stdio.h>

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

int main(void)
{
	student a = { "kim", 20, 4.3 };
	student b = { "park", 21, 4.2 };
	return 0;
}

포인터

다른 변수의 주소를 가지고 있는 변수이다. 포인터가 가리키는 내용의 변경: * 연산자 사용

  • & 연산자: 변수의 주소를 추출
  • * 연산자: 포인터가 가리키는 곳의 내용을 추출포인터의 종류

int *p;   // pint형 변수를 가리키는 포인터

float *pf; // pfdouble형 변수를 가리키는 포인터

char *pc; // pcchar형 변수를 가리키는 포인터

 

함수의 파라미터로서의 포인터
#include <stdio.h>
void swap(int* px, int* py)
{
	int tmp;
	tmp = *px;
	*px = *py;
	*py = tmp;
}
main()
{
	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);
}

배열과 포인터

배열의 이름 : 사실상의 포인터와 같은 역할

#define _CRT_SECURE_NO_WARNINGS
#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);
	}
	return sum;
}
int main(void)
{
	int list[SIZE];
	get_integers(list);
	printf("합 = %d \n", cal_sum(list));
	return 0;
}

구조체와 포인터

구조체의 요소에 접근하는 연산자: ->

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.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);
	}
	strcpy(p->name, "Park");
	p->age = 20;
	free(p);
	return 0;
}

동적 메모리 할당

  • 프로그램의 실행 도중에 메모리를 할당 받는 것
  • 필요한 만큼만 할당을 받고 또 필요한 때에 사용하고 반납
  • 메모리를 매우 효율적으로 사용가능

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