no image
[C++] 백준 5단계 - 9086번 문제
문제설명 소스코드 #include using namespace std; int main() { int N; string input; cin >> N; for (int i = 0; i > input; cout
2023.04.02
no image
[C++] 백준 5단계 - 2743번 문제
문제설명 소스코드 #include using namespace std; int main() { string input; cin >> input; cout
2023.04.02
no image
[C++] 백준 5단계 - 27866번 문제
문제설명 소스코드 #include using namespace std; int main() { string input; int n; cin >> input >> n; cout
2023.04.01
no image
[C++] 백준 4단계 - 1546번 문제
문제설명 소스코드 #include using namespace std; int main() { int N; int max = 0; double score = 0; cin >> N; double* arr = new double[N]; for (int i = 0; i > arr[i]; if (arr[i] > max) max = arr[i]; } for (int i = 0; i < N; ++i) { if (arr[i] == max) { score += 100; continue; } score += (arr[i] / max) * 100; } cout
2023.04.01
no image
[C++] 백준 4단계 - 10811번 문제 (바구니 뒤집기)
문제설명 소스코드 #include using namespace std; int main() { int N; int M; cin >> N >> M; int* arr = new int[N]; //동적 할당 int a; int b; for (int i = 0; i > a >> b; for (int j = 0; j > M; int* arr = new int[N]; int a; int b; for (int i = 0; i > a >> b; for (int j = 0; j
2023.03.31
no image
[C++] 백준 4단계 - 3052번 문제
문제설명 소스코드 #include using namespace std; int main() { int array[42] = {}; int input; for (int i = 0; i > input; ++array[input % 42]; } int count = 0; for (int i = 0; i 0) ++count; cout
2023.03.31
no image
[컴퓨터 구조] 레지스터
이 글은 혼자 공부하는 컴퓨터 구조 + 운영체제 (저자 : 강민철)의 책과 유튜브 영상을 참고하여 개인적으로 정리하는 글임을 알립니다. 반드시 알아야 할 레지스터 프로그램 카운터 명령어 레지스터 메모리 주소 레지스터 메모리 버퍼 레지스터 플래그 레지스터 범용 레지스터 스택 포인터 베이스 레지스터 프로그램 카운터 메모리에서 가져올 명령어의 주소(메모리에서 읽어 들일 명령어의 주소)를 저장 프로그램 카운터를 명령어 포인터라고 부르는 CPU도 있음 명령어 레지스터 방금 읽어 들어 들인 명령어를 저장하는 레지스터 제어장치는 명령어 레지스터 속 명령어를 받아들이고 해석한 뒤 제어 신호를 내보냄 메모리 주소 레지스터 메모리의 주소를 저장하는 레지스터 CPU가 읽고자 하는 주소 값을 주소 버스로 보낼 때 메모리 주소..
2023.03.31
no image
[C++] 백준 4단계 - 5597번 문제
문제설명 소스코드 #include using namespace std; int main() { int arr[30] = { 0 }; int input = 0; for (int i = 0; i > input; arr[input - 1] = 1; } for (int i = 0; i < 30; ++i) if (arr[i] != 1) cout
2023.03.30

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main() {
	int N; string input;
	cin >> N;
	for (int i = 0; i < N; ++i)
	{
		cin >> input;
		cout << input[0] << input[input.length() - 1] << endl;
	}
}

 

풀이

C++에서는 string이라는 자료형을 제공한다.

string 자료형은 편리한 함수들을 많이 제공하는데, 그 중에서 하나가 바로 length()함수이다.

length()함수는 문자열의 길이를 리턴한다. 또한 string 자료형은 배열처럼 인덱싱을 할 수 있기 때문에 위 코드처럼 작성하면 된다.

문제설명

소스코드

#include <iostream>
using namespace std;
int main() {
	string input;
	cin >> input;
	cout << input.length() << endl;
}

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main() {
	string input; int n;
	cin >> input >> n;
	cout << input[n - 1]; //string형은 char형 배열처럼 사용할 수 있다.
}

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main() {
	int N; int max = 0; double score = 0;
	cin >> N;
	double* arr = new double[N];
	for (int i = 0; i < N; ++i)
	{
		cin >> arr[i];
		if (arr[i] > max) max = arr[i];
	}
	for (int i = 0; i < N; ++i)
	{
		if (arr[i] == max)
		{
			score += 100;
			continue;
		}
		score += (arr[i] / max) * 100;
	}
	cout << score / N;
}

 

풀이

세준이가 3과목 10점, 20점, 30점을 받았다면, ((10/30 X 100) + (20/30 X 100) + (30/30 X 100)) / 3 을 출력하면 된다.

효율이 떨어질지라도 나는 첫 번째 for문에서 값을 입력받고 최댓값을 구하고, 두 번째 for문에서 점수의 총합을 계산하였다.

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main() {
	int N; int M;
	cin >> N >> M;
	int* arr = new int[N]; //동적 할당
	int a; int b;
	for (int i = 0; i < N; ++i) arr[i] = i + 1; //배열 초기화
	for (int i = 0; i < M; ++i)
	{
		cin >> a >> b;
		for (int j = 0; j <= (b - a) / 2; ++j)
		{
			int tmp = 0;
			tmp = arr[j + a - 1];
			arr[j + a - 1] = arr[b - j - 1];
			arr[b - j - 1] = tmp;
		}
	}
	for (int i = 0; i < N; ++i) cout << arr[i] << " ";
}

 

풀이

  • 1부터 N까지 수 중에서 i부터 j까지의 수를 역순으로 M번 정렬한다.

내가 작성한 소스코드는 기본적으로 swap 알고리즘을 기초로 만들어졌다.

swap알고리즘의 내용 이전에 내가 작성한 https://rebugs.tistory.com/143 에서 확인할 수 있다.

 

[JAVA] 배열 요소를 역순으로 정렬하는 알고리즘

Do it! 자료구조와 함께 배우는 알고리즘 입문[자바편] 연습문제와 실습문제입니다. 배열의 요소가 1, 2, 3, 4, 5, 6, 7 이렇게 7개 있다고 하면 역순으로 정렬하면 7, 6, 5, 4, 3, 2, 1이다. 그림에서 보는

rebugs.tistory.com

위 포스팅의 응용버전이 이번 문제인 것 같다.

자세한 스왑 과정을 확인하려면 아래와 같은 코드로 과정을 지켜보면 된다.

#include <iostream>
using namespace std;
int main() {
	int N; int M;
	cin >> N >> M;
	int* arr = new int[N];
	int a; int b;
	for (int i = 0; i < N; ++i) arr[i] = i + 1;
	for (int i = 0; i < M; ++i)
	{
		cin >> a >> b;
		for (int j = 0; j <= (b - a) / 2; ++j)
		{
			int tmp = 0;
			tmp = arr[j + a - 1];
			cout << arr[j + a - 1] << "와 " << arr[b - j - 1] << "를 바꿉니다." << endl;
			arr[j + a - 1] = arr[b - j - 1];
			arr[b - j - 1] = tmp;
		}
		for (int i = 0; i < N; ++i) cout << arr[i] << " ";
		cout << endl;
	}
	for (int i = 0; i < N; ++i) cout << arr[i] << " ";
}

문제설명

 

소스코드

#include <iostream>
using namespace std;
int main() {
	int array[42] = {};
	int input;
	for (int i = 0; i < 10; ++i)
	{
		cin >> input;
		++array[input % 42];
	}
	int count = 0;
	for (int i = 0; i < 42; ++i) if (array[i] > 0) ++count;
	cout << count;
}

 

풀이

0으로 초기화된 42칸짜리 배열을 선언하고, 입력을 42로 나눈 나머지를 a라고 하면, 좀 전에 선언한 배열의 a번째 인덱스를 1증가 시킨다.

for문을 돌려서 0보다 큰 배열의 개수를 센 후 출력한다.

나머지가 같은 수가 있다면, array[나머지]가 1증가하게 된다.

왜 42칸짜리 배열을 선언하는가?
어떠한 수든 42로 나눈 나머지는 0~41이기 때문에 42칸짜리 배열을 선언하는 것이다.

 

이 글은 혼자 공부하는 컴퓨터 구조 + 운영체제 (저자 : 강민철)의 책과 유튜브 영상을 참고하여 개인적으로 정리하는 글임을 알립니다.


반드시 알아야 할 레지스터

  1. 프로그램 카운터
  2. 명령어 레지스터
  3. 메모리 주소 레지스터
  4. 메모리 버퍼 레지스터
  5. 플래그 레지스터
  6. 범용 레지스터
  7. 스택 포인터
  8. 베이스 레지스터

 

프로그램 카운터

  • 메모리에서 가져올 명령어의 주소(메모리에서 읽어 들일 명령어의 주소)를 저장
  • 프로그램 카운터를 명령어 포인터라고 부르는 CPU도 있음

 

명령어 레지스터

  • 방금 읽어 들어 들인 명령어를 저장하는 레지스터
  • 제어장치는 명령어 레지스터 속 명령어를 받아들이고 해석한 뒤 제어 신호를 내보냄

 

메모리 주소 레지스터

  • 메모리의 주소를 저장하는 레지스터
  • CPU가 읽고자 하는 주소 값을 주소 버스로 보낼 때 메모리 주소 레지스터를 거침

 

메모리 버퍼 레지스터

  • 메모리와 주고받을 값(데이터와 명령어)을 저장하는 레지스터
  • CPU가 데이터 버스로 주고받을 값은 메모리 버퍼 레지스터를 거침

 


 

메모리에 저장된 프로그램을 실행하는 과정에서 프로그램 카운터, 명령어 레지스터, 메모리 주소 레지스터, 메모리 버퍼 레지스터에 어떤 값들이 담기는가?

1. 메모리에 실행할 프로그램이 1000번지부터 1500번지까지 저장되어 있다고 가정하고, 1000번지에는 2진수 1101이 저장되어 있다고 가정하자

2. 프로그램을 처음부터 실행하기 위해 프로그램 카운터에는 1000이 저장된다. 이는 메모리에서 가져올 명령어가 1000번지에 있다는 것을 의미

3. 1000번지를 읽어 들이기 위해서 주소 버스로 1000번지를 내보내야한다. 이를 위해 메모리 주소 레지스터에는 1000이 저장된다.

4. '메모리 읽기' 제어 신호와 메모리 주소 레지스터 값이 각각 제어 버스와 주소 버스를 통해 메모리로 보내진다.

5. 메모리 1000번지에 저장된 값은 데이터 버스를 통해 메모리 버퍼 레지스터로 전달되고, 프로그램 카운터는 증가되어 다음 명령어를 읽어 들일 준비를 한다.

프로그램 카운터
메모리에서 현재 실행할 값인 1101을 메모리 버퍼 레지스터로 이동되었으니 프로그램 카운터는 1001번지 데이터를 읽어 들인다. 이 과정이 반복되면서 CPU는 프로그램을 차례대로 실행해 나간다. 결국 CPU가 메모리 속 프로그램을 순차적으로 읽어 들이고 실행해 나갈 수 있는 이유는 CPU속 프로그램 카운터가 꾸준히 증가하기 때문이다.

 

6. 메모리 버퍼 레지스터에 저장된 값은 명령어 레지스터로 이동한다.

 

7. 제어장치는 명령어 레지스터의 명령어를 해석하고 제어 신호를 발생시킨다.

 

범용 레지스터

  • 범용 레지스터는 일반적인 상황에서 자유롭게 사용할 수 있는 레지스터이다.
  • 다른 레지스터는 특정 용도가 있지만 범용 레지스터는 용도가 다양함
  • 범용 레지스터는 CPU 내에서 여러개가 존재

 

플래그 레지스터

  • 연산 결과 또는 CPU 상태에 대한 부가적인 정보를 저장하는 레지스터

 

스택 주소 지정 방식(특정 레지스터를 이용한 주소 지정방식 1)

스택 포인터, 베이스 레지스터는 주소 지정에 사용될 수 있는 특별한 레지스터이다.

스택 포인터는 스택 주소 지정 방식이라는 주소 지정 방식에 사용되고, 프로그램 카운터와 베이스 레지스터는 변위 주소 지정 방식이라는 주소 지정 방식에 사용된다.

스택 주소 지정 방식은 스택과 스택 포인터를 이용한 주소 지정 방식이다.

스택 포인터란 스택의 꼭대기를 가리키는 레지스터이다. 즉, 스택 포인터는 스택에 마지막으로 저장한 값의 위치를 저장하는 레지스터이다.

 

스택은 어디에 있을까?
스택은 메모리 안에 있다. 정확히는 메모리 안에 스택처럼 사용할 영역이 정해져 있다. 이를 스택 영역이라고 한다.

 

 

변위 주소 지정 방식(특정 레지스터를 이용한 주소 지정 방식 2)

변위 주소 지정 방식이란 오퍼랜드 필드 값(변위)과 특정 레지스터의 값을 더하여 유효 주소를 얻어내는 주소 지정 방식이다.

변위 주소 지정 방식을 사용하는 명령어는 연산 코드 필드, 어떤 레지스터의 값과 더할지를 나타내는 레지스터 필드, 주소를 담고 있는 오퍼랜드 필드가 있다.

이때, 변위 주소 지정 방식은 오퍼랜드 필드의 주소와 어떤 레지스터를 더하는지에 따라 상대 주소 지정 방식, 베이스 레지스터 주소 지정 방식 등으로 나뉜다.

 

상대 주소 지정 방식

오퍼랜드와 프로그램 카운터의 값을 더하여 유효 주소를 얻는 방식이다.

프로그램 카운터에는 읽어 들일 명령어의 주소가 저장되어 있다. 만약 오퍼랜드가 음수(-3)라면 CPU는 읽어 들이기로 한 명령어로부터 -3번지로 접근한다.

오퍼랜드가 +3이라면 아래와 같다.

 

베이스 레지스터 주소 지정 방식

오퍼랜드와 베이스 레지스터의 값을 더하여 주소를 얻는 방식이다.

베이스 레지스터는 '기준 주소', 오퍼랜드는 '기준 주소로부터 떨어진 거리' 로서의 역할을 한다.

즉, 베이스 레지스터 주소 지정 방식은 베이스 레지스터 속 기준 주소로부터 얼마나 떨어져 있는 주소에 접근할 것인지를 연산하여 유효 주소를 얻어내는 방식이다.

문제설명

소스코드

#include <iostream>
using namespace std;
int main() {
	int arr[30] = { 0 };
	int input = 0;
	for (int i = 0; i < 28; ++i)
	{
		cin >> input;
		arr[input - 1] = 1;
	}
	for (int i = 0; i < 30; ++i) if (arr[i] != 1) cout << i + 1 << endl;
}