문제

신입 단기과제 연계 끝에 대전멤버십에서 새로운 숫자 체계 "MemNumber"를 완성시켰다. 이것은 4개의 소문자 m, c, x, i와 8개의 숫자 2, 3, 4, 5, 6, 7, 8, 9로 수를 표현한다. 즉, 0과 1은 사용하지 않는다.

 

몇가지 예를 들면

  • "5m2c3x4i" 는 5234 (= 5*1000 + 2*100 + 3*10 + 4*1)
  • "m2c4i" 는 1204 (= 1000 + 2*100 + 4*1)
  • "5m2c3x" 는 5230 (= 5*1000 + 2*100 + 3*10)

위 예에서

  • "5m" 는 5000 (= 5*1000)
  • "2c" 는 200 (= 2*100)
  • "3x" 는 30 (= 3*10)
  • "4i" 는 4 (= 4*1)

즉, m, c, x, i 앞에 2부터 9까지 수가 올 수 있는데 이 수와 짝을 이루어 수의 곱을 의미한다.

m, c, x, i 는 많아야 한 번 나올수 있다. 접두 숫자와는 같이 움직인다. m , c ,x , i 는 이 순서로 나와야 한다. 

다음은 가능하지 않는 "MemNumber"이다.

  • "1m2c4i"
  • "mcc4i"
  • "m2c0x4i"
  • "2cm4i"

 

"MemNumber" 문자열 두개를 입력으로 받아 "MemNumber" 수의 합을 구한 후 대응되는 "MemNumber" 문자열을 출력한다.

 

입력

"MemNumber" 문자열 2개가 입력된다.

두 수의 합은 9999를 넘지 않는다.

 

출력

입력된 "MemNumber" 문자열의 합을 "MemNumber"수로 출력한다.

예제 입력1

xi x9i

예제 출력1

3x


예제 입력2

i 9i

예제 출력2

x


예제 입력3

m2ci 4m7c9x8i

예제 출력3

5m9c9x9i


예제 입력4

9m8c7xi c2x8i

예제 출력4

9m9c9x9i



[문제 설명]

m = 1000

c = 100

x = 10

i = 1

1. 이 4개의 문자들은 2~9까지의 8개의 숫자와 짝을 이룹니다.

따라서 4m = 4 * 1000 = 4000이라고 볼 수 있고, mc = 1000 + 100 = 1100이라고 볼 수 있습니다.

2. mcxi는 각 한 번씩만 나올 수 있습니다.

3. m - c - x - i 꼭 이 순서대로 문자가 나와야 합니다.

이 세 가지 조건을 만족하면서 두 수의 합을 계산 한 후 다시 m, c, x, i 로 표현을 하는 것이 이번 문제였습니다.


[소스 코드 설명]

입력받은 문자의 길이를 구한 후, 그 길이 만큼 for문을 돌면서 각 문자별로 앞에 붙은 숫자와 짝을 이루어 입력받은 문자가 숫자로 환산하면 몇 인지를 파악합니다.

그리고 환산한 두 숫자를 더한 후에 다시 mcxi 문자로 바꿔주는 소스 코드 입니다.



Posted by 밍쫑
,

문제

멤버마을 멤버집에 살고 있는 우리 친구 현수는 축구를 너~~무 좋아해요♥

멤버학교에 새로 입학한 신입들을 데리고 축구를 하러 나가려는 찰나!! 멤버마을의 촌장인 미스타 "손"은 피곤한 신입들을 보호하고자 현수를 가로막습니다. 옆에서 지켜보고 있던 멤버마을의 부촌장인 새로운 "손"은 한가지 제안을 합니다. 

 

"마을에 쯔쯔가무시가 돌고 있다. 쥐를 잡아와라. 그렇다면 축구를 허락하겠다!"

축구를 너무 사랑하는 우리 친구 현수를 돕기 위해서 다함께 고양이(CAT)를 한마리 찾아볼까요?

 

입력된 문자열에 C, A, T가 순서대로 들어있다면 "YES"를 출력하고,

순서가 섞여 있거나 혹은 없다면 "NO"를 출력하세요.

 

입력

문자열의 길이는 1~50개이며, 'A' 부터 'Z' 이 이외의 문자는 없다.

 

출력

고양이를 찾으면 "YES"

못찾으면 "NO" 

예제 입력1

XCYAZTX

예제 출력1

YES


예제 입력2

CTA

예제 출력2

NO


예제 입력3

SGHDJHFIOPUFUHCHIOJBHAUINUIT

예제 출력3

YES


예제 입력4

CCCATT

예제 출력4

NO

 

HINT

고양이는 한 마리만 잡읍시다! 사료값 아끼자구요!



[문제 풀이]

순서대로 "CAT"이라는 단어가 순서대로 한 번만 존재해야하지만  "YES"가 출력되는 문제이다.

꼭 붙어있을 필요는 없고, 예제 이력 4를 보면 CAT가 하나 있는 것처럼 볼 수도 있겠지만!

CCCATT, CCCATT, CCCATT, CCCATT, CCCATT, CCCAT로 여러가지의 CAT이 나오므로 출력은 NO라고 볼 수 있다.



[소스코드 설명]

변수 cat은 사용자의 입력이 들어가게 되고, cat2에는 C, A, T일 경우, 그 단어를 받아들이는 임시 변수라고 보면 된다.

그리고 여기서 cat2.find("CAT"); 라는 것을 썼는데, 그것은 C++에서 제공하는 find()함수를 이용하여 cat2에 CAT이 존재하는지를 찾아주는 함수이다.

string::find

CString 개체의 문자열 기준, 좌측에서부터 문자 혹은 문자열을 검색한다.


string::find()를 통하여 원하는 단어나 문장을 검색 후 

그것이 문자열에 있는지 없는지string::npos를 통하여 알 수가 있다.

(string::find()는 찾고자 하는 단어나 문자열이 없으면 string::npos를 리턴한다.)



Posted by 밍쫑
,
프로그램 명: luckynum(open)
제한시간: 1 초
4 나 7로 이루어져있는 수를 행운의 숫자라고 한다.

다음은 처음 5개의 행운의 숫자다.

4, 7, 44, 47, 74...

정수 k가 주어졌을 때 k번 째 행운의 숫자를 구하는게 문제다.

입력

정수 k( 1<= k <= 10^9) 가 주어진다.

출력

k번 째 행운의 숫자를 출력한다.

입출력 예

입력

5

출력 

74
출처: 2010-2011 October COCI Q3
번역+추천: likepad


[문제 풀이]

4, 7, 44, 47, 74, 77, 444, 447, 474, 477, 744, 747, 774, 777, ....


[소스코드 설명]

이번 문제는 재귀함수를 이용해서 풀어보았습니다.


재귀(再歸, Recursion)는 수학이나 컴퓨터 과학 등에서 자신을 정의할 때 자기 자신을 재참조하는 방법을 뜻한다. 주로 이 방법은 함수에 적용한 재귀 함수(Recursion Function)의 형태로 많이 사용된다. 또, 사진이나 그림 등에서 재귀의 형태를 사용하는 경우도 있다.

- Wiki, 위키백과 -


일단 위에 문제 풀이를 보시면서 규칙이 보이시나요?

만약 제 이전 알고리즘 포스팅을 보신 분이라면 어떤 규칙인지 아실텐데요.

네, 바로 홀수번째와 짝수번째로 나뉘어진 규칙입니다.

홀수 : 4, 44, 74, 444, 474, 744, 774, ...    // 4로 끝나고 있다.

짝수 : 7, 47, 77, 447, 477, 747, 777, ...    // 7로 끝나고 있다.


1의자리가 홀수번째에는 4이고, 짝수번째에는 7로 나타나고 있습니다.



'알고리즘 > for' 카테고리의 다른 글

[for문] 약수의 개수, 총합 (1일차)  (0) 2014.04.15
[for문]1의 위치 (1일차)  (0) 2014.04.15
Posted by 밍쫑
,
프로그램 명: ft
제한시간: 1 초

자연수가 입력으로 주어진다. 이 수의 약수를 출력하고 , 다음 줄에는 약수의 개수 , 다음 줄에는 약수의 총합 , 다음 줄에는 약수의 곱의 일의 자리수를 출력한다.

입력

주어지는 수는 1000 이하의 자연수이다.

출력

입출력 예

입력

6

출력

1 2 3 6
4
12 

6


[문제 풀이]

문제는 크게 어려운 부분이 없습니다.

입력한 숫자의 약수와 약수의 갯수와 그 약수들의 곱을 구하는 문제입니다.


[소스코드 설명]

저는 먼저, 약수의 갯수를 세주는 count를 선언해주었습니다.

그리고 입력된 값 n이 for문을 돌면서 나누어 떨어지면 약수가 맞기 때문에 arr 배열에 값을 넣어주고 count값을 증가시켜주는 식으로 했습니다.



'알고리즘 > for' 카테고리의 다른 글

[for문] 행운의 숫자(lucky number) (1일차)  (1) 2014.04.16
[for문]1의 위치 (1일차)  (0) 2014.04.15
Posted by 밍쫑
,
프로그램 명: bit_pos
제한시간: 1 초

양의 정수 n 을 입력으로 받아 이 수를 이진수로 나타내었을 때 1 이 나타나는 위치를 구하는 것이 문제이다.

수를 이진수로 나타내었을 때 가장 오른쪽의 자리를 LSB(Least Significant Bit)라 한다. LSB 를 0 번 위치로 간주한다.

입력

양의 정수 n 이 입력으로 주어진다. ( 1 <= n <= 10^6 )

출력

1 이 나타나는 위치를 모두 출력한다.

입출력 예

입력

13

출력

0 2 3 

출처: Central European Programming Contest 


[문제 풀이]

이 문제의 경우 10진수를 2진수로 바꾼 후에 1이 나타나는 위치를 찾는 문제입니다.

주어진 예제에서 13의 경우 2진수로 바꾸면 1101 이 됩니다.

문제에서 제일 오른쪽에서부터 0으로 시작한다 하였으니, 

현재 1이 나타나는 위치는 오른쪽에서부터 순서대로 0, 2, 3이 됩니다.

 1

 0

1

1

 0

 1

[소스코드 설명]

저는 짝수일 때와 홀수 일때에 대해서 따로 생각을 했습니다.


홀수 : 0001(1), 0011(3), 0101(5), 0111(7), 1001(9), 1011(11), 1101(13), ...

짝수 : 0010(2), 0100(4), 0110(6), 1000(8), 1010(10), 1100(12), 1110(14), ...


혹시 규칙이 보이시나요?

홀수의 경우 0의 자리가 무조건 1로 끝나고, 짝수의 경우 0의 자리가 무조건 0으로 끝나게 됩니다.

그래서 저는 "isFirst" 라는 것을 선언해서 홀수면서 처음나누어지는 것에 대해서는 무조건 1임을 나타내서 출력할 때 0도 포함이 되게 하였습니다.(1011)


그 다음 10진수를 2진수로 바꾸는 것을 손으로 직접 해보시면 아시겠지만, N값이 1이 될 때까지 계속 나눕니다. 따라서 N이 1이되면 break;로 계산을 멈추게 하였습니다.


그리고 2진수로 바꾸는 것이기 때문에 한 번 계산이 끝날 때마다 N값을 N/2로 갱신해주었습니다.



'알고리즘 > for' 카테고리의 다른 글

[for문] 행운의 숫자(lucky number) (1일차)  (1) 2014.04.16
[for문] 약수의 개수, 총합 (1일차)  (0) 2014.04.15
Posted by 밍쫑
,

단기 집중 교육의 5일차 입니다.

교육 마지막날! 전문가 과정이라 어려운 것도 있는데.. 매일 이 과제 저 과제 하느라 밤새다보니

복습도 못하고, 수업때 졸고... 좋은 수업 놓친게 많아서 큰일이네요..

마지막 날 강의도 포스팅 열심히 정리해보겠습니다.


오늘의 시작은 재귀호출입니다.



파일명 : 1.c




파일명 : 2.c

버블 소트

정렬이 끝난 빨간색은 나중에 아직 정렬되지 않은 것들을 정렬할 때에는 빼고 정렬해야한다.

그러므로 소스 코드 중에서 for(j=0; j < len -1 - i; j++) 주의해야한다.


선택 정렬(selection sort)

위에 소스에서 void sort() 부분만 조금만 수정되었습니다.




빠른 정렬(Quick Sort)




파일명 : 3.c

알고리즘 교체 전략



//오름차순과 내림차순 정렬이 중복되어 있는 소스코드
#include  <stdio.h>

#define swap(x, y, T) do { T t = x; x= y; y = t; } while(0)

void ask_sort(int arr[], int len) {
	int i, j;
	for(i=0 ; i<len-1 ; i++){
		for(j=0 ; j<len-1 -i ; j++){
			if(arr[j] > arr[j+1])
				swap(arr[j], arr[j+1], int);
		}
	}
}

void des_sort(int arr[], int len) {
	int i, j;
	for(i=0 ; i<len-1 ; i++){
		for(j=0 ; j<len-1 -i ; j++){
			if(arr[j] < arr[j+1])
				swap(arr[j], arr[j+1], int);
		}
	}
}

void display(int arr[], int len) {
	int i;
	for(i=0;i<len;i++)
		printf("%2d ", arr[i]);
	getchar();
}

void main() {
	int arr[10] = {1,3,5,7,9,2,4,6,8,10};

	display(arr,10);
	ask_sort(arr, 10);
	display(arr,10);
	des_sort(arr, 10);
}

2

파일명 : 4.c

메모리 누수 탐지 프로그램의 구현

5



0.asm


0.cpp


0.exe


0.obj


1.c


2.c


3.asm


3.c


3.exe


3.obj




Posted by 밍쫑
,

파일명 : 1.c

파일명 : 0.c

파일명 : 4.c

파일명 : flexible_array.c

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

typedef struct {
	int age;
	char *name;	//메모리에 낭비되지 않게 힙에다가 만듭신다.
} PERSON;	//힙에 만듭시다.

void main() {
	int age;
	char name[32];
	PERSON *p;

	printf("input name: ");
	scanf("%s", name);
	printf("input age: ");
	scanf("%d", age);

	p = (PERSON*)malloc(sizeof(PERSON));
	p->age = age;
	
	p->name=(char*)malloc(strlen(name)+1);	//strlen은 null을 포함하지않으니까 +1해준다.
	strcpy(p->name, name);

	printf("name: %s, age: %d\n", p->name, p->age);

	free(p->name);
	free(p);
}



ppt 8쪽

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

typedef struct {
	int age;
	char name[1];	//개발자의 편법! 1글자도 아니고 null만 들어가는데?
} PERSON;	//힙에 만듭시다.

void main() {
	int age;
	char name[32];
	PERSON *p;

	printf("input name: ");
	scanf("%s", name);
	printf("input age: ");
	scanf("%d", age);

	p = (PERSON*)malloc(sizeof(PERSON)+ sizeof(char)*strlen(name));	//위에서 말한 개발자의 편법!
	p->age = age;
	
	p->name=(char*)malloc(strlen(name)+1);	//strlen은 null을 포함하지않으니까 +1해준다.
	strcpy(p->name, name);

	printf("name: %s, age: %d\n", p->name, p->age);

	free(p->name);
	free(p);
}

  • int arr[0];    //배열의 길이는 0을 설정할 수 없다.
  • typedef struct{
    int arr[0];
    } TYPE;

    void main() {
        TYPE type; 
        printf("%d\n", sizeof(type));    //4가 출력된다. 포인터의 타입에 따른..
    }

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

typedef struct {
	int age;
					// 99년도에 표준 되었다. C99
	char name[];	//char name[0];	//->flexible array member
			//사이즈가 안 잡혀있는데 도대체 무슨 역할을하는걸까?(ppt10~11쪽)
} PERSON;

//반드시 flexible array member는 구조체의마지막에 와야한다.

void main() {
	// printf("%d\n", sizeof(PERSON));	//4가 나옴.

	int age;
	char name[32];
	PERSON *p;

	printf("input name: ");
	scanf("%s", name);
	printf("input age: ");
	scanf("%d", age);

	p = (PERSON*)malloc(sizeof(PERSON)+ sizeof(char)*strlen(name) + 1);	 

//null값 포함하기 위해서 +1 그럼 런타임 에러 안남. p->age = age; p->name=(char*)malloc(strlen(name)+1); strcpy(p->name, name); printf("name: %s, age: %d\n", p->name, p->>age); free(p->name); free(p); }

파일명 ; 3.c

#include <stdio.h>
#include <stdlib.h>	//for systme()

#define Q_MAX	(5)

int queue[Q_MAX];
int front, rear;

void put(int data) {
	queue[rear] = data;
	rear++;
}

int get() {
	int t = queue[front];
	front++;
	return t;
}

void display(){
	int i;
	system("cls");

	printf("%*s\n", (rear+1)*4, "rear");
	printf("%*s\n", (rear+1)*4, " | ");

	for(i=0; i<Q_MAX; i++){
		printf("[%2d]", queue[i]);
	}
	printf("\n");

	printf("%*s\n", (front+1)*4, " | ");
	printf("%*s\n", (front+1)*4, "front");

	getchar();
}

void main() {
	int i;
	display();
	for(i=0;i<6;i++){
		put(i+1);
		display();
	}

	for(i=0;i<6;i++){
		get();
		display();
	}
}

큐가 비어 있는 경우 : front == rear

큐가 가득 차 있는 경우 : front == rear

->큐가 가득 차 있는 경우와 비어 있는 경우를 구분할 수가 없다.

//큐는 full과 empty를 구분하기 힘들다는 단점이 있다.
#include <stdio.h>
#include <stdlib.h>	//for systme()

#define Q_MAX	(5)

int queue[Q_MAX];
int front, rear;

void put(int data) {
	queue[rear] = data;
	
	//if(rear != Q_MAX)
	//	rear++;
	//else
	//	rear = 0;

	rear = (rear+1)% Q_MAX;
}

int get() {
	int t = queue[front];

	//if(front != Q_MAX)
	//	front++;
	//else
	//	front = 0;
	front = (front+1)% Q_MAX;
}

void display(){
	int i;
	system("cls");

	printf("%*s\n", (rear+1)*4, "rear");
	printf("%*s\n", (rear+1)*4, " | ");

	for(i=0; i<Q_MAX; i++){
		printf("[%2d]", queue[i]);
	}
	printf("\n");

	printf("%*s\n", (front+1)*4, " | ");
	printf("%*s\n", (front+1)*4, "front");

	getchar();
}

void main() {
	int i;
	display();
	for(i=0;i<6;i++){
		put(i+1);
		display();
	}

	for(i=0;i<6;i++){
		get();
		display();
	}
}

큐 구현!!

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

#define Q_MAX	(5)

int queue[Q_MAX];
int front, rear;

void put(int data) {
	queue[rear] = data;


	rear = (rear+1)% Q_MAX;
}

int get() {
	int t = queue[front];

	front = (front+1)% Q_MAX;
}

int is_full() { return front == (rear+1) % Q_MAX; }
int is_empty() { return front == rear; }

void display(){
	int i;
	system("cls");

	printf("%*s\n", (rear+1)*4, "rear");
	printf("%*s\n", (rear+1)*4, " | ");

	for(i=0; i<Q_MAX; i++){
		printf("[%2d]", queue[i]);
	}
	printf("\n");

	printf("%*s\n", (front+1)*4, " | ");
	printf("%*s\n", (front+1)*4, "front");

	getchar();
}

void main() {
	int i;
	display();
	for(i=0;i<6;i++){
		if(!is_full())
			put(i+1);
		display();
	}

	for(i=0;i<6;i++){
		if(!is_empty())
			get();
		display();
	}
}

큐의 문제점 : 큐가 전역에 존재한다. 그러므로 하나밖에 마들 수가 없다. 2개 이상을 만들려면 배열이 필요하다.

a

a

a

a

a




0.c

1.c

2.c

3.c

4.c

android_dynamic_array.c

flexible_array.c



Posted by 밍쫑
,

Last In First Out의 구조를 가진 " Stack "에 대해서 배워보자!

ex) 식당 아주머니는 식판을 아래에서부터 쌓아올리지만, 식판을 가져가는 우리는 위에서부터 가져간다!

     지역 변수의 사용

- 수직적인 구조이다.

- push : 스택이라는 메모리에 데이터를 저장하는 인터페이스

- pop :  스택이라는 메모리부터 데이터를 꺼내오는 인터페이스











프로젝트명 : 20140212

파일명 : 1.c


// 스택(Stack) : LIFO(Last In First Out)
// ex)식당에서의 식판, 지역 변수의 사용

// push : 스택이라는 메모리에 데이터를 저장하는 인터페이스
// pop : 스택이라는 메모리부터 데이터를 꺼내오는 인터페이스

#include <stdio.h>

#define MAX_SIZE	(5)

int arr[MAX_SIZE];
int idx;	//초기화해주지 않아도, os가 자체적으로 0으로 초기화

//push의 경우 뭘로 return할지 굳이 표시하지 않아도 된다.
void push(int data) {
	arr[idx++] = data;
	/* arr[idx] = data;	//최초의 push의 경우 0부터 시작한다고 했으니
	++idx; */
}

int pop() {
	return arr[--idx];
	/*
	--idx;
	return arr[idx]; */
}

//참(0 이외의 수)과 거짓(0)을 나타내려면 int 타입을 쓴다.
int is_full() {
	return (idx == MAX_SIZE);
	/*
	if(idx == MAX_SIZE)
		return 1;
	else
		return 0;
	*/
}

int is_empty() {
	return (idx ==0);
	/*
	if(idx ==0)
		return 1;
	else
		return 0;
	*/
}

void main() {
	int i;

	for(i=0; i<10; i++) {
		if(!is_full())	//가득 차 있지 않아야 push가능
			push(i+1);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty())
			printf("%d\n", pop());
	}
}



step 1. 가장 간단한 스택의 구현

#include <stdio.h>

#define MAX_SIZE	(5)

int arr[MAX_SIZE];
int idx;	//초기화해주지 않아도, os가 자체적으로 0으로 초기화

void push(int data) {arr[idx++] = data;}
int pop() {	return arr[--idx]; }
int is_full() { return (idx == MAX_SIZE); }
int is_empty() { return (idx ==0); }

void main() {
	int i;

	for(i=0; i<10; i++) {
		if(!is_full())	//가득 차 있지 않아야 push가능
			push(i+1);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty())
			printf("%d\n", pop());
	}
}

step2. 하나 이상의 자료구조 구현

//step 2. 하나 이상의 자료구조 구현!
#include <stdio.h>

#define MAX_SIZE	(5)

// 데이터 추상화를 ADT(Abstract Data Type)
typedef struct __STACK {
	int arr[MAX_SIZE];
	int idx;
} STACK;

int arr[MAX_SIZE];
int idx;	//초기화해주지 않아도, os가 자체적으로 0으로 초기화

void push(int data, STACK *s) { s->arr[(s->idx)++] = data; }
int pop(STACK *s) {	return s->arr[--(s->idx)];}
int is_full(STACK *s) {	return (s->idx == MAX_SIZE);}
int is_empty(STACK *s) { return (s->idx ==0);}

void main() {
	int i;
	STACK s = {0, };	//이 데이터를 어떻게 처리할지는 라이브러리 개발하고 분석한 사람만 사용할 수 있다.
	//라이브러리 개발자가 저 스택을 초기화해줘야한다. -> step3

	for(i=0; i<10; i++) {
		if(!is_full(&s))	//가득 차 있지 않아야 push가능
			push(i+1, &s);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty(&s))
			printf("%d\n", pop(&s));
	}
}

step3. 자료구조의 초기화를 위한 인터페이스 지급

// step 3 : 자료구조의 초기화를 위한 인터페이스 지급
// 스택의 크기가 고정되어있고,  사용자가 우너하는 시점에 메모리를 할당해야하기때문ㅇ ㅔ자료구조로...->step4
#include <stdio.h>

#define MAX_SIZE	(5)

// 데이터 추상화를 ADT(Abstract Data Type)
typedef struct __STACK {
	int arr[MAX_SIZE];
	int idx;	// =0;	//?
} STACK;

void init_stack(STACK *s) { s->idx = 0; }
void push(int data, STACK *s) { s->arr[(s->idx)++] = data; }
int pop(STACK *s) {	return s->arr[--(s->idx)];}
int is_full(STACK *s) {	return (s->idx == MAX_SIZE);}
int is_empty(STACK *s) { return (s->idx ==0);}

void main() {
	int i;
	STACK s;
	init_stack(&s);

	for(i=0; i<10; i++) {
		if(!is_full(&s))	//가득 차 있지 않아야 push가능
			push(i+1, &s);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty(&s))
			printf("%d\n", pop(&s));
	}
}

step4. 자료 구조를 힙에 구현

// step 4.  자료구조를 힙에 구현
#include <stdio.h>
#include <stdlib.h>

typedef struct __STACK {
	#define MAX_SIZE	(5)
	int *arr;	//힙에 구현
	int idx;
} STACK;

void init_stack(STACK *s) { 
	s->arr = (int*)malloc(sizeof(int)*MAX_SIZE);
	s->idx = 0;
}
void push(int data, STACK *s) { s->arr[(s->idx)++] = data; }
int pop(STACK *s) {	return s->arr[--(s->idx)];}
int is_full(STACK *s) {	return (s->idx == MAX_SIZE);}
int is_empty(STACK *s) { return (s->idx ==0);}

void main() {
	int i;
	STACK s;
	init_stack(&s);

	for(i=0; i<10; i++) {
		if(!is_full(&s))	//가득 차 있지 않아야 push가능
			push(i+1, &s);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty(&s))
			printf("%d\n", pop(&s));
	}
}

step5. 범용 타입에 대한 설계------------------------------

// step 5. 범용 타입에 대한 설계
#include <stdio.h>
#include <stdlib.h>

typedef struct __STACK {
	#define MAX_SIZE	(5)
	int *arr;	//모든 타입이 다 되게 해야 될 때는 void 포인터 타입으로
	int idx;
} STACK;

void init_stack(STACK *s) { 
	s->arr = (int*)malloc(sizeof(int)*MAX_SIZE);
	s->idx = 0;
}
void push(int data, STACK *s) { s->arr[(s->idx)++] = data; }
int pop(STACK *s) {	return s->arr[--(s->idx)];}
int is_full(STACK *s) {	return (s->idx == MAX_SIZE);}
int is_empty(STACK *s) { return (s->idx ==0);}

void main() {
	int i;
	STACK s;
	init_stack(&s);

	for(i=0; i<10; i++) {
		if(!is_full(&s))	//가득 차 있지 않아야 push가능
			push(i+1, &s);	//1 2 3 4 5 6 7 8 9 10
	}

	for(i=0; i<10; i++) {
		if(!is_empty(&s))
			printf("%d\n", pop(&s));
	}
}

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


// 스택의 내부 자료구조를 리스트로 구현!
#include <stdlib.h>
#include <stdio.h>

typedef struct __NODE
{
	int data;
	struct __NODE *next;
} NODE;

typedef struct __STACK
{
	int idx;	// 스택에 저장된 위치
	int size;	// 스택의 크기
	struct __NODE *head;
} STACK;

void init_stack(STACK *s, int size)
{
	s->idx = 0;
	s->size = size;
	s->head = 0;
}

void push(int data, STACK *s) {
	NODE *cur;
	NODE *node = (NODE*)malloc(sizeof(NODE));
	node->data = data;
	node->next = 0;

	// 리스트가 비어 있는 경우
	if(s->head ==0) {
		s->head = node;
		++(s->idx);
		return;
	}

	// 리스트가 비어 있지 않은 경우
	cur = s->head;
	while(cur->next)
		cur = cur->next;

	cur->next = node;
        ++(s->idx);

}



int pop(STACK *s)
{
	int data;
	NODE *prev = s->head;
	NODE *cur = s->head;

	while(cur->next)
	{
		prev = cur;
		cur = cur->next;
	}

	data = cur->data;
	prev->next = 0;
	--(s->idx);
	free(cur);

	return data;
}

int is_full(STACK *s) { return s->size == s->idx; }
int is_empty(STACK *s) { return s> idx == 0; }

void main()
{
	int i;

	STACK s;
	init_stack(&s, 3);

	for(i = 0; i < 4; i++)
	{
		if(!is_full(&s)) push(i+1, &s);
	}

	for(i = 0; i < 4; i++)
	{
		if(!is_empty(&s)) printf("%d\n", pop(&s));
	}
}

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

파일명 : 2.c


//비트셋(Bitset, Bitmap
// LED 제어 프로그램 - 메모리의 낭비가 일어나고있다.
#include <stdio.h>
#include <stdlib.h>


enum { LED0 = 0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 };
enum { LED_OFF = 0, LED_ON = 1 };
void main()
{
	int i;
	char mmio[8] = {0, };

	// LED ON
	mmio[LED1] = LED_ON;
	mmio[LED3] = LED_ON;

	// LED CHECK
	for(i=0;i<8;i++){
		if(mmio[i] == LED_ON)
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}
	getchar(); system("cls");

	// LED OFF
	mmio[LED3] = LED_OFF;

	// LED CHECK
	for(i=0;i<8;i++){
		if(mmio[i] == LED_ON)
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}
}

위의 소스코드는 메모리의 낭비라는 문제점이 있다. 다음 소스코드는 그를 수정하였다.

// 문제점: 메모리의 낭비
#include <stdio.h>
#include <stdlib.h>

enum { LED0 = 0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 };
enum { LED_OFF = 0, LED_ON = 1 };

// 비트 연산으로 변경해보세요!

// 시프트 연산자

// 데이터 << 이동할 비트 수
// 데이터 >>  이동할 비트 수

// LED 제어 프로그램 - 메모리의 낭비가 일어나고있다.

void main()
{
	int i;
	char mmio = 0;	// // char mmio[8] = { 0, };

	// LED ON
	mmio = mmio | (LED_ON << LED1);	// 0000 0000 mmio = 0
									// 0000 0010 LED_ON	<< LED1
									// --------- |(OR)
									// 0000 0010
	
	mmio |= LED_ON >> LED3;			// 복합 대입 연산자의 사용
	// 규칙 1. 특정 비트를 설정하려면 OR 연산자를 사용해야 한다!


	// 0000 1010
	// 0000 0010	// 마스크 비트
	// --------- &
	// 0000 0010

	// LED CHECK
	for(i=0; i<8; i++)
	{
		if(mmio & (LED_ON << i))	// 0000 1010 & 1 << i
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}
	// 규칙 2. 특정 비트를 검사하려면 &연산자를 사용해야 한다.

	getchar(); system("cls");

	// LED OFF
	//mmio[LED3] = LED_OFF;	// 0000 1010
							// 1111 0111	~(LED_ON << LED3)
							// --------- &
							// 0000 0010
	mmio &= ~(LED_ON << LED3); //비트를 끈거다.

	// 규칙 3. 특정 비트를 초기화하려면 &연산자와 비트 반전 연산자(~)
	// 를 사용해야 한다.

	// LED CHECK
	for(i=0; i<8; i++)
	{
		if(mmio & (LED_ON << i))
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}
}

c

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

#define BIT_SET(i , x)  ((x[i/32]) |= (1>>(i%32)))
#define BIT_ISSET(i , x) ((x[i/32]) & (i >>(>i%32)))
#define BIT_CLR(i , x)  ((x[[i/32]) &= ~(i <>>(i%32)))

enum { LED0 = 0, LED1, LED2, LED3, LED4, LED5, LED6, LED7 };
enum { LED_OFF = 0, LED_ON = 1 };

// 비트 연산으로 변경해보세요!

// 시프트 연산자

// 데이터 << 이동할 비트 수
// 데이터 >> 이동할 비트 수

void main()
{
	int i;
	//char mmio = 0;	// 32비트 -> 128비트
	int mmio[32] = {0,};
	// LED ON

	BIT_SET(LED1, mmio);
	BIT_SET(1000, mmio);
	//mmio = mmio | (LED_ON <<LED1);	// 0000 0000 mmio = 0
	// 0000 0010 LED_ON	<< LED1
	// --------- |(OR)
	// 0000 0010

	// 복합 대입 연산자의 사용



	for (i = 0; i<1024; i++)
	{
		if (BIT_ISSET(i, mmio))	// 0000 1010 & 1 << i
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}

	getchar(); system("cls");


	mmio &= ~(LED_ON << LED3);


	// LED CHECK
	for (i = 0; i<128; i++)
	{
		if (BIT_CLR(i, mmio))
			printf("LED%d ON\n", i);
		else
			printf("LED%d OFF\n", i);
	}
}

e

f

파일명 : 3.c

//Dynamic Array
#include <stdio.h>

#define ARR_SIZE(x)	(sizeof(arr)/sizeof(*arr))

int sum_arr(int arr[]) {
	int i, sum = 0;
	for(i=0;i<ARR_SIZE(arr);i++) {
		sum += arr[i];
	}
	return sum;
}

void main() {
	int i, sum = 0;
	int arr[] = {1,2,3,4,5,6,7,8,9,10};

	//for(i=0;i<ARR_SIZE(arr);i++)
	//	sum += arr[i];

	printf("sum=%d\n", sum_arr(arr));
}

a

//이 소스코드의 단점 : 배열에 있는 컨텐츠를 저장하는데, 저장되는 타입이 int이다. 
//근데 앞으로 double, float, char타입의 배열이 만들수도있는거다. 
//즉 모든 것이 성립하는 void 타입으로 바꿔야 할것이다.
//즉 int타입만 저장 가능하다
#include <stdio.h>
#include <stdlib.h>	//calloc 사용하기 위해서 선언한다.

typedef struct __Array {
	int capacity;
	int *content;
} Array;

Array* createArray(int capacity) {
	Array *arr = (Array*)calloc(1, sizeof(struct __Array));
	arr->content = (int*)calloc(capacity, sizeof(int));
	arr->capacity = capacity;

	return arr;
}

int setElement(Array *arr, int index, int data) {
	int capacity = arr->capacity;
	if(index <0 || index >=capacity)
		return -1;

	arr->content[index] = data;
	return 0;
}

int getElement(Array *arr, int index) {
	int capacity = arr->capacity;
	if(index <0 || index >capacity) {
		fprintf(stderr, "out of index");
		exit(-1);
	}

	return arr->content[index];
}

int getCapacity(Array *arr) { return arr->capacity; }

int sum_arr(Array *arr) {
	int i, sum = 0;
	for(i=0;i<getCapacity(arr);i++)
		sum +=getElement(arr, i);
	return sum;
}

void main() {
	int i;
	Array *arr = createArray(5);	//int arr[5];만든것과 동일

	for(i=0;i<getCapacity(arr);i++) {
		setElement(arr, i, i+1); //arr[i] = i+1;
	}

	printf("sum = %d\n", sum_arr(arr));

	/*for(i=0;i<getCapacity(arr);i++)
		printf("arr[%d] = %d\n", i, getElement(arr, i));
		printf("arr[%d] = %d\n", i, arr[i]);	//이건 안된다. 왜냐하면 arr은 배열이아니라 구조체니까 */
 }


// 문제점: 특정 타입만을 저장할 수 있음!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct __Array
{
	int capacity;
	void **content;
} Array;

Array* createArray(int capacity)
{
	Array *arr = (Array*)calloc(1, sizeof(struct __Array));
	arr->content = (void**)calloc(capacity, sizeof(void*));
	arr->capacity = capacity;

	return arr;
}

void* setElement(Array *arr, int index, void *pointer)
{
	void *old;
	int capacity = arr->capacity;
	if(index < 0 || index>= capacity)
	{
		fprintf(stderr, "out of index");
		exit(-1);
	}


	old = arr->content[index];	// backup
	arr->content[index] = pointer;
	return old;
}

void* getElement(Array *arr, int index)
{
	int capacity = arr->capacity;
	if(index < 0 || index > capacity)
	{
		fprintf(stderr, "out of index");
		exit(-1);
	}

	return arr->content[index];
}

int getCapacity(Array *arr) { return arr->capacity; }

typedef struct
{
	char name[32];
	int  age;
} PERSON;


void main()
{
	int i;
	PERSON *p;
	Array *arr = createArray(5);	// int arr[5];
									// int[] arr = new int[5];
	for(i = 0; i < getCapacity(arr); i++)
	{
		p = (PERSON*)malloc(sizeof(PERSON));
		strcpy(p->name, "kkk");
		p->age = i+1;

		setElement(arr, i, p); // arr[i] = i+1;
	}

	for(i = 0; i < getCapacity(arr); i++)
	{
		p = (PERSON*)getElement(arr, i);
		printf("arr[%d] = %s, %d\n", i, p->name, p->age);
	}


	// printf("sum = %d\n", sum_arr(arr));

	//for(i = 0; i< getCapacity(arr); i++)
	//	printf("arr[%d] = %d\n", i, getElement(arr, i));	// printf("arr[%d] = %d\n", i, arr[i]);
}

// append 기능 추가
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct __Array
{
	int capacity;
	int size;	//배열의 현재 크기
	void **content;

} Array;

Array* createArray(int capacity)
{
	Array *arr = (Array*)calloc(1, sizeof(struct __Array));
	arr->content = (void**)calloc(capacity, sizeof(void*));
	arr->capacity = capacity;

	return arr;
}

void* setElement(Array *arr, int index, void *pointer)
{
	void *old;
	int capacity = arr->capacity;
	if(index < 0 || index >= capacity)
	{
		fprintf(stderr, "out of index");
		exit(-1);
	}


	old = arr->content[index];	// backup
	arr->content[index] = pointer;
	return old;
}

int addElement(Array *arr, void *pointer) {
	int size = arr->size;
	int capacity = arr->capacity;

	if(size == capacity)
		return -1;

	arr->content[size] = pointer;
	arr->size++;

	return 0;
}

void* getElement(Array *arr, int index)
{
	int capacity = arr->capacity;
	if(index < 0 || index > capacity)
	{
		fprintf(stderr, "out of index");
		exit(-1);
	}

	return arr->content[index];
}

int getCapacity(Array *arr) { return arr->capacity; }
int getSize(Array *arr) {return arr->size; }

typedef struct
{
	char name[32];
	int  age;
} PERSON;

void display(Array *arr){
	PERSON *p;
	int i;

	system("cls");
	for(i=0;i<getSize(arr);i++){
		p = (PERSON*)getElement(arr, i);
		printf("arr[%d] = %s, %d\n", i, p->name, p->age);
	}
	getchar();
}

void main()
{
	int i;
	PERSON *p;
	Array *arr = createArray(5);

	display(arr);
	for(i = 0; i < getCapacity(arr); i++)
	{
		p = (PERSON*)malloc(sizeof(PERSON));
		strcpy(p->name, "kkk");
		p->age = i+1;

		addElement(arr, p);

		display(arr);
	}

	for(i = 0; i < getCapacity(arr); i++)
	{
		p = (PERSON*)getElement(arr, i);
		printf("arr[%d] = %s, %d\n", i, p->name, p->age);
	}
}



1.c

2.c

3.c



Posted by 밍쫑
,

이 날은 아이디어 생각하고 수강신청 도와주려다가 밤을 새는 바람에....많이 졸아서 필기가 영 부족하다 ㅠㅠ..

그래서 대신 강사님의 소스 파일을 공유하고자 합니다.



1일차에 이어서 동일하게 프로젝트를 생성합니다.


프로젝트명 : 20140211


1일차 복습하고 시작합니다.

파일명 : 1.c



파일명 : 2.c

// void 포인터
#include <stdio.h>

void swap(int *a, int *b) {
	int t = *a;
	*a = *b;
	*b = t;
}

void swap(int *a, int *b) {
	short t = *a;
	*a = *b;
	*b = t;
}

void swap(int *a, int *b) {
	char t = *a;
	*a = *b;
	*b = t;
}

void main() {
	int a = 30, b = 1000;
	swap(&a, &b);
	printf("a = %d, b = %d\n", a, b);
}

c언어에서는 동일한 이름의 함수이름들을 전부 swap이 _swap으로 바뀐다.


그래서 swap_xx함수 이름을 바꿔준다. -> swap_int

a

// void 포인터
#include <stdio.h>

void swap_int(int *a, int *b) {
	int t = *a;
	*a = *b;
	*b = t;
}

void main() {
	int a = 30, b = 1000;
	swap(&a, &b);
	printf("a = %d, b = %d\n", a, b);
}

전처리 기능은 문자열을 단순히 치환만 하기 때문에 .....

// void 포인터
#include <stdio.h>

#define SWAP(x,y,T) do { 
T t = a; 
a - b; 
b= t; 
} while(0)

void main() {
	int a = 30, b = 1000;
	//swap(&a, &b);
	SWAP(a, b, int);
	printf("a = %d, b = %d\n", a, b);
}

하나의 함수를 여러 타입을 핸들링하고 싶은 것의 문제이다..!

함수가 어떤 타입이 되든지 간에 모두 SWAP을 하려면 중간에 있는 임시 변수를 char로 한 바이트를 주고

아래 소스 코드는 타임에 의존적이지 않는 generic swap을 만든것이다.


#include <stdio.h>

/*#define SWAP(x,y,T) do { 
T t = a; 
a - b; 
b= t; 
} while(0) */
void swap(void *a, char *b, int size) {
	char t;
	char *aa = (char*)a;
	char (bb = (char*)b;
	int i;

	for(i=0;i


파일명 : 3.c






파일명 : 4.c









알아둡시다!!

구조체와 포인터


구조체 포인터 연산자: (*)., / ->

// 자기 참조 구조체 : 자기 자신의 타입에 대한 포인터


파일명 : 5.c



메모리를 보통 노드라고 한다.

리스트 자료구조 : 데이터를 저장하기 위한 메모리 -> 노드(node)

본인의 마지막 노드를 터미널이라고 한다. 종료 노드와 시작 노드를 구분하기 위해서 마지막 노드에 null을 넣어 놓는다.

끝을 tail이라고 한다.

리스트 자료구조 구현 방법은 여러개 있다.


파일명 : 6.c






한 방향으로 연결된 노드의 경우!

만약 3000개가 연결되었다.. 근데 찾고자하는게 마지막에 있다면??? 최악이지 않은가...

그래서 배울게 바로!! reverse() - PPT 13p : 기존의 display()는 head부터 시작한다. 따라서 tail부터 시작하는 reverse용 display를 따로 만들어야 된다.

void reverse(NODE *head, NODE *tail){
	NODE *prev = head;
	NODE *curr = head->next;
	NODE *next;

	while(cur != tail) {
		next = curr->next;
		curr->next = prev;
		prev = curr;
		curr = next;
	}

	curr->next = prev;
}

a

문제점이 있다면, 어떤게 reverse로 보고 어떤것을 reverse_display로 봐야 할지 모른다. 근데 별 쓸모없는 기능이다.

그리고 이 함수는 역방향(reverse)에 대한 순방향 복원이 안된다. 오버헤드가 크다!!

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

typedef struct __NODE
{
	int data;
	struct __NODE *next;
	struct __NODE *prev;	//double linked list!
} NODE;

void init_list(NODE *head)
{
	head->next = head;
	head->prev = head;
}

//PPT 17p
void insert_front(NODE *head, NODE *node)
{
	node->next = head->next;
	head->next = node;

	node->prev = node->next->prev;
	node->next->prev = node;
}

void insert_end(NODE *head, NODE *node)
{
	NODE *cur = head;

	while(cur->next != head)
		cur = cur->next;

	node->next = cur->next;
	cur->next = node;
}

void reverse(NODE *head)
{
	NODE *prev = head;
	NODE *curr = head->next;
	NODE *next;

	while(curr != head)
	{
		next = curr->next;
		curr->next = prev;
		prev = curr;
		curr = next;
	}

	curr->next = prev;
}

void display(NODE *head)
{
	NODE *node;

	system("cls");
	printf("\n[head]->");
	for(node = head->next; node != head; node = node->next)
		printf("[%d]->", node->data);
	printf("[head]");
	getchar();
}



void main()
{
	int i;

	NODE head;

	NODE arr[5];

	init_list(&head);

	display(&head);
	for(i = 0; i < 5; i++)
	{
		arr[i].data = i+1;
		//insert_front(&head, &arr[i]);
		insert_end(&head, &arr[i]);
		display(&head);
	}

	reverse(&head);
	display(&head);

	reverse(&head);
	display(&head);
}

// 역방향에 대한 순방향 복원이 안된다!

양방향 노드를 이용하면 라이브러리의 최고 동력을 살릴 수 있지만, 메모리는 2배 희생이 필요하다.

이 양방향 노드를 더블 링크라고 한다.




1.c


2.c


3.c


4.c


5.c


6.c







Posted by 밍쫑
,

집중 단기 시작 세미나 ('자료구조와 알고리즘')

2014년 2월 10일~ 2월 14일 진행


강형민 외부 강사님(checkdisk@ioacademy.co.kr)

강의 시간 : 10시 ~ 17시


사용할 언어 : C언어

개발환경 : MS Visual Studio 2010


1일차     : 고급 C 언어

2~3일차 : 자료구조(리스트, 트리, 스택, 큐, ...)

4~5일차 : 알고리즘(압축, 암호화, 패턴 매칭, ...)

마지막 날에 테스트 볼 예정. 시험 난이도는 수업시간에 배운 내용 정도




1. 

프로젝트명 : 20140210

추가 옵션 : 빈 프로젝트 체크



2. 솔루션 탐색기의 소스 파일 폴더에서 새 항목을 추가한다.


3. c++파일을 선택하고 파일명은 1.c로 준다.

확장명이 c언어가 없다. 하지만 c언어로 만들 수 있다. 확장자를 통해서 c++/c를구분한다.

따라서 c언어로 개발을 할 경우 *.cpp를 선택 한 후 파일 이름을 쓴 후확장명을 *.c로 해주어야한다. )


4. 소스코드 작성 후 디버깅하지 않고 시작(Ctrl + F5)을 한다.


5.

1.c 파일의 속성에서 '빌드에서 제외' - '예' 로 바꿔준다.


6. 빌드에서 제외 됬음이 나타난 것을 확인한다.

decay 사용하는 이유는 성능상의 오버헤드를 줄이기 위해서이다.

int arr[3];의 경우, arr이 전체 타입인 int를 따른다. 하지만 


배열을 선언할 때에는 배열의 심봉를 항상 타입과 길이 사이에 와야 한다.(중요중요!)



#include <stdio.h>

// arr와 &arr의 의미

void main()
{
	int arr[3];

	arr;	// 배열의 시작주소, 타입은 첫 번째 원소
	&arr;	// 배열의 시작주소, 타입은 배열 전체

	printf(" arr = 0x%p\n", arr);
	printf("&arr = 0x%p\n", &arr);
}

#include <stdio.h>

// arr와 &arr의 의미

void main()
{
	int arr[3];

	int *p1 = arr; // 1. 일중 포인터 : 다른 지역에 있는 메모리에 접근하기 위해서 사용
	int [3] *p2 = &arr /*하지만 (중요중요!)때문에 int *p2[3] = &arr;을 해야하는데 이 경우 오류이다.
	첫번째 심볼을 찾고 뒤에 있는 기호를 본다. 여기서 심볼은 p2. 뒤에 있는 [이다. 따라서 배열! 
		이게 포인터변수인 것을 알리려면 int (*p2)[3]2.배열 포인터으로 해 줘야 한다.
		이때 p1은 일중포인터 p2는 배열 포인터라고 한다.*/

	printf(" arr = 0x%p\n", arr);
	printf("&arr = 0x%p\n", &arr);
}


파일명 : 4.c

#include <stdio.h>
void main() {
	int arr[2][3];	// 원소의 갯수는 몇 개?

int arr[2][3]; 이것은 사실 2차원 배열의 원소가 아니라 1차원 배열이다.

2차원 배열은 2차원이 아니라 1차원 배열의 확장이다.

따라서 위의 것을 다시 쓰면 int[3] int[2];라 쓸수 있고, 이것은 int 타입의 길이가 3개인 1차원 배열을 원소로 하는 1차원 배열이다.



#include <stdio.h>

void foo(int arr[][3]) {

}

void main() {
	int arr[2][3]; // int arr[][3] = arr; // int arr[][3] = arr;	//error, 함수의 매개변수에 특화된 문법
}

11111111111111
 

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

void foo(int (*arr)[][3]) {
}

void main() {
	int arr[2][3]; // int arr[][3] = arr; // int arr[][3] = arr;	//error, 함수의 매개변수에 특화된 문법
int (*pArr)[3] = arr }

테스트1! 힙에 행은 2개이고 열은 3개인 int타입의 동적 2차원 배열을 선언해보세요!

#include <stdio.h>
#include <stdlib.h>
void main() {
  int(*p)[3] =  malloc(sizeof(int)*2*3); // 왜 malloc에서 빨간 줄이 나타난걸까?

지금 우리의 컴파일러는 cpp컴파일러이기 때문에


for(int i=0;i<2;i++) {
  for(int j=0;j<3;j++) 
   p[i][j] = 3;
 }

  for(int i=0; i<2; i++) {
   for(int j=0; j<3; j++) 
    printf("%d\n", p[i][j]); 
  }
}

여기서 컴파일 에러가 없고, 분명 실행도 잘 되는데 malloc 부분에서 빨간 줄이 나 있을 것이다. 이것은 현재 우리의 컴파일러가 cpp컴파일이기 때문에 그런 것이지, 소스 코드 상의 문제는 없는 것이다.

malloc의 빨간 줄이 신경 쓰이는 경우(암식적인 표현)에는 명시적 표현으로 바꿔준다.
int(*p)[3] = (int(*)[3])malloc(sizeof(int)*2*3); //이 경우 cpp컴파일러에서 빨간 줄이 나타나지 않을것이다.
하지만 이와 같은 경우 c언어 스타일이기 때문에 cpp스타일로 가려면 
static_cast<int(*)[3]>(malloc....);을 넣어주면된다.


파일명 : 5.c

2차원 배열이 왜 2차원이 아닌가?

여기서 배열의 주소는 왜 0부터 시작할까? .........

포인터와 포인터의 사칙연산은 되지 않지만, 제한적인 연산은 가능하다.

#include <stdio.h>
// 포인터의 연산은 사칙 연산은 불가능하나
// 제한적인 연산은 가능하다. void main() {
	int *p, *q;

	p + q;	/*과연 실제로 안될까?된다. 
			이것을 값으로 볼지 주소로 볼지를 선택하는건 사용자의 선택인데, 
			이 경우 컴파일러가 막은 것이다.
			보안상의 위험성을 방지하고자 OS가 죽여버린다.
			주소와 주소가 더해지면은 의미없는 주소가 나올 확률이 높다.
			이것을 역참조해서 찾아가면 허가없는 메모리 참조가 되지 않을까요?
			그러므로 컴파일 에러를 내는 것이 좋다. 그래서 컴파일러가 막는 것이다.*/
	p - q;	//포인터 - 포인터 = 정수
	p * q;	//곱셈은 덧셈의 연속이기 때문에 되지 않는다.
	p / q;
}

p + q의 경우, 실제로는 되는 연산이다. 

하지만 이것을 값으로 볼지 주소로 볼지를 선택하는건 사용자의 선택인데, 이 경우 컴파일러가 막은 것이다.

보안상의 위험성을 방지하고자 OS가 죽여버린다.

주소와 주소가 더해지면은 의미없는 주소가 나올 확률이 높다.

이것을 역참조해서 찾아가면 허가없는 메모리 참조가 되지 않을까?

그러므로 컴파일 에러를 내는 것이 좋다. 그래서 컴파일러가 막는 것이다.


외웁시다!

//포인터 + 정수 = 포인터

// 포인터 - 정수 = 포인터

// 포인터 - 포인터 = 정수


테스트2! 다음 배열에서 첨자 연산을 사용하지 않고 배열의 중간값을 구해보세요.


void main() {
	int arr[5] = {1,2,3,4,5}; 
	int *center =??????????; //&arr[2];//&arr[2];

	printf("%d\n", *center);	//3
}




배열 첨자 연산




void main(){
	int arr[2][3] = {{1,2,3},{4,5,6}};

	printf("%d\n", arr[1][2]);

	printf("%d\n", *(arr+1)[2]);
	//printf(" arr = 0x%p\n", arr);
	//getchar();
	//printf("arr+1 = 0x%p\n", arr+1);/
}
/*이와같이 비정상적인 연산 값이 나온다.
별표보다 첨자가 우선이다. 그러므로 행 단위부터 접근하기 위해서 별표를 먼저 해석시키기 위해
(*(arr+1))을 해야한다.*/

// 결론 : 2차원 배열은 이중 포인터가 아니다.

void main() {
	int arr[2][3] = {1,2,3,4,5,6};

	printf("%d\n", **arr);	// 1이 나온다. 
				// 이것은 arr[0][0] = *(*(arr + 0) + 0); 와 같다. 
				// 결국 2차원 배열은 2중 포인터처럼 보인다. 0이 전부 상쇄되고 있다.
				// 이것은 어느순간 죽게 되어 있다. 이것은 그저 1차원 포인터의 확장일 뿐..
}


파일명 : 8.c


//이중 포인터의 개념

#include <stdio.h>
int div(int a, int b) {
	 return a/b;
}
void main() {
	int a = 4, b = 2;

	printf("%d\n", div(a,b));
} 



return -1;의 리턴 결과 값이 숫자 -1일지 에러 코드 값 -1일지 헷갈리므로 좋은 코드는 아니다.그래서 C++나 Java에서는 예외처리로 해준다.


void main() {
	char name[1024];

	printf("input name: ");
	scanf("%s", name);
	
	printf("your name: %s\n", name);
}

좋은 코드가 아니다. 왜냐하면 사용자로부터 이름을 5번 입력받는다면 이 코드가 5번이 있어야된다.. 이렇게 반복되는 코드는 함수로 빼는게 좋다. (밑에 get_name() 부분)





정리!!!

일중 포인터를 쓰는 이유는 다른 지역의 일반 변수의 심볼에 접근하기 위하여 사용!

이중 포인터를 쓰는 이유는 다른 지역의 포인터 변수의 심볼에 접근하기 위하여 사용!





파일명 : 9.c

이러한 포인터 배열은 쓰는 이유는 모든 데이터를 힙에다가 저장하기 위해서



//3개의 이름을 저장하는 프로그램을 구현해보자!
void mian() {
	char names[3][1024];

	int i;
	for(i=0;i<3;i++) {
		printf("input name: ");
		scanf("%s", names[i]);
	}

	for(i=0;i<3;i++) {
		printf("name[%d]: %s", i, names);
	}
}
/*이 프로그램은 메모리 낭비가 심하다*/

asdf1





삼중 포인터


	//삼중포인터
#include <stdio.h>

void get_name(char** *p) {

}

void main() {
	char **names;

	get_name(&names);
}

숙제!! 이중 포인터를 삼중포인터로 바꾸기


파일명 : a.c

함수의 선언 : 함수의 심볼은 반드시 리턴 타입과 매개 변수 사이에 위치해야한다.

리턴타입 함수명([파라미터, ...]);








void(* hoo())(int) : 심볼은 hoo인데 앞에는 포인터 뒤에는 함수호출연산자. 뒤가 함수호출이니까 hoo는 함수호출연산자

void(* zoo( void(*fp)(int)))(int) : 심볼은 zoo인데 리턴하는 것은 포인터인데 포인터의 타입은 int이다. 함수포인터를 리턴하고 있다..


근데 누가 이렇게 길고 복잡하게 쓸까? 아니..안쓴다. 그래서 alias(별명)을 붙여서 쓴다.






1.c


2.c


3.c


4.c


5.c


6.c


7.c


8.c


9.c


Posted by 밍쫑
,