반응형

저번 시간에는 스트링 라이브러리에 있는 함수들을 배웠고, 그 함수들의 예제를 공부해봤습니다.

 

이번 시간에는 더 다양한 함수들을 배워보겠습니다.

 

1. gets, puts

 

gets는 빈칸, tab을 포함한 새로운 문자열 입력 방식으로 엔터 전까지 모두 입력 받게 됩니다.  

 

cin과 다른 점은 띄어쓰기까지 받아낸다는 것입니다.

 

puts는 gets와 짝을 이루어 문자열을 출력하는 함수로 문자열 출력 후 자동으로 줄을 바꾸어줍니다.

 

그런데 이런 gets가 c++ 최신 버전에는 삭제가 되었습니다.

https://www.zinnunkebi.com/c-gets-fgets/

 

C언어 gets함수를 사용해서는 안되는 이유

gets함수는 읽어들이는 문자열의 길이를 지정하지 않기때문에 문자열을 저장하는 메모리 버퍼의 크기보다 더 많은 문자열을 읽는 경우 오류가 발생합니다.

www.zinnunkebi.com

그래서 gets가 안된다고 당황하지마시고 get_s나 fgets를 쓰면 됩니다.

 

그림 1

2. strncpy(원하는 개수의 문자만 복사)

 

이 함수는 strncpy(복사받을 배열명, "복사할 문자나 배열명", 복사할 문자수)이렇게 활용되게 됩니다. 

 

그런데 이것을 그냥 하게 되면 문제가 발생합니다.

 

그림 2

 

그림 2처럼 문제가 발생하는데 이 때는 #define _CRT_SECURE_NO_WARNINGS 이거를 써주시면 됩니다.

 

그림 3

 

문자열을 복사하다보니 minsu의 앞 4글자 n=mins까지 가져오게 됩니다. 그런데 출력이 될 때 mins가 아니라 minsoo is good이 출력이 됩니다.

 

이는 원래 문자열의 끝을 컴퓨터는 NULL로써 파악하게 되는데 그렇기 때문에 NULL이 나오는 good뒤에까지 쭉 출력을 하게 됩니다.

 

아니면 NULL을 추가해줘야 됩니다.

 

그림 3

 

이렇게 하면 mins만 출력 되는 것을 알 수 있습니다.

 

3. strncat (더하기 역할)

 

배열에 이미 있는 문자열 뒤에 지정한 문자만큼 이어붙이는 역할입니다.

 

활용을 할 때는 strncat(복사받을 배열명, "복사할 배열명", 복사받을 글자수)으로 활용을 하면 됩니다.

 

 

그림 4

 

strncat을 써서 mins를 복사한 값이 원래 Name에 들어간 것을 알 수 있습니다.

반응형
반응형

https://www.acmicpc.net/problem/1940

 

1940번: 주몽

첫째 줄에는 재료의 개수 N(1 ≤ N ≤ 15,000)이 주어진다. 그리고 두 번째 줄에는 갑옷을 만드는데 필요한 수 M(1 ≤ M ≤ 10,000,000) 주어진다. 그리고 마지막으로 셋째 줄에는 N개의 재료들이 가진 고

www.acmicpc.net

 

풀이과정 1

 

1. 일단 받을 재료의 수, 갑옷이 완성되는 번호의 합을 입력받는다. 그리고 재료들을 입력받는다.

 

2. 재료들을 정렬을 해주어야한다. 그 다음에 시작인덱스와 끝인덱스를 정해서 완성되는 번호의 합이 몇개가 나오는지 출력하면 된다.

 

3. 정렬은 알고리즘 헤더파일의 sort 정렬을 이용하자

 

4. 시작인덱스를 고정시키고, 끝 인덱스를 뒤에서부터 시작인덱스까지 이동시키며 두개의 합이 갑옷이 완성되는 합이 되는 지 판단한다. 그리고 시작인덱스를 한 칸 이동시키고 이 과정을 반복한다.

 

#include <iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin.tie(NULL);

	int num;// 받을 재료의 수
	cin >> num;
	int sum;// 완성되는 번호의 합
	cin >> sum;
	vector<int> A(num, 0);

	for (int i = 0;i < num;i++) {
		cin >> A[i];
	}

	sort(A.begin(), A.end());

	int count = 0;

	for (int i = 0;i < num;i++) {
		for (int j = num - 1;j > i;j--) {
			if(A[i]+A[j]==sum){
				count++;
			}
		}
	}
	cout << count;
}

 

for문을 사용하면 이렇게 풀 수 있고, while문을 사용하면 밑의 처럼 풀 수 있다.

#include <iostream>
#include<string>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin.tie(NULL);

	int num;// 받을 재료의 수
	cin >> num;
	int sum;// 완성되는 번호의 합
	cin >> sum;
	vector<int> A(num, 0);

	for (int i = 0;i < num;i++) {
		cin >> A[i];
	}

	sort(A.begin(), A.end());

	int count = 0;
	int i = 0;
	int j = num - 1;
	while(i<j){
		if (A[i] + A[j] < sum) {
			i++;
		}
		else if (A[i] + A[j] > sum) {
			j--;
		}
		else {
			count++;
			i++;
			j--;
		}

	}
	cout << count;
}
반응형
반응형

 

이 문제의 시간 제한은 2초, N의 최댓값은 100000000이므로 제한 시간을 맞추기 위해서 투 포인트를 사용해야 합니다.

 

시작 인덱스와 종료 인덱스를 지정하여 연속된 수를 표현해보자

 

풀이 방식을 두 가지 정도 생각해보았습니다.

 

첫번째 풀이 방식

 

1. 시작인덱스부터 종료 인덱스까지 탐색하면서 합이 N이 될 때를 카운트한다.

 

2. 만약 sum하고 N 값이 같을 때는 종료 인덱스를 더 큰 쪽으로 한 칸 옆으로 보내고, sum값을 바뀐 종료 인덱스를 더 한 값으로 초기화한다. 그리고 count도 시켜준다.

 

3. 만약 sum보다 N이 작을 때는 종료 인덱스를 더 큰 쪽으로 한 칸 옆으로 보내고, sum값을 바뀐 종료 인덱스를 더 한 값으로 초기화한다.

 

4. 만약 sum이 N보다 작다면 sum에서 시작인덱스 값을 빼주고,  시작인덱스를 더 큰 쪽으로 한 칸 옆으로 보낸다. 

 

#include <iostream>
#include<string>

using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin.tie(NULL);

	int num;
	cin >> num;
	int sum = 0;
    int start index=1;
    int end_index=1;
    int sum=1
	int count = 0;

	while(end_index !=N){
    	if(sum==N){
        count++;
        end_index++;
        sum+=end_index;
        }
        else if(sum>N){
        	sum+=start_index;
            start_index++;
        }
        else{
        	end_index++;
            sum+=end_index;
            }
        }      
	cout << count+1;
}

 

 

두 번째 방식

 

1. for문을 활용해서 1부터 N 전까지 반복시킨다.

 

2. 만약 N의 값이 sum보다 작아지면 sum을 0으로 초기화 시킨다.

 

3. 만약 N의 값이 sum 값하고 같다면 count를 하고 sum을 0으로 초기화시킨다.

 

4. 만약 N값이 sum보다 크다면 그 반복문의 해당하는 숫자를 더해준다. 

 

#include <iostream>
#include<string>

using namespace std;

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cin.tie(NULL);

	int num;
	cin >> num;
	int sum = 0;
	int count = 0;

	for (int i = 1;i < num;i++) {
		for(int j=i;j<num;j++)
			if (num < sum) {
				sum = 0;
				break;
			}
			else if (num == sum) {
				count++;
				sum = 0;
				break;
			}
			else {
				sum += j;
			}
	}
	cout << count+1;

}

 

반응형
반응형

앞에서 문자열 배열과 포인터 배열을 통해서 문자열을 어떻게 나타내고 두 개의 차이가 무엇인지 배웠습니다.

 

이번 시간에는 이같이 문자열을 쓸 때마다 배열을 쓰지 않고 편하게 쓸 수 있는 방법을 알려드리도록 하겠습니다. 그리고 활용법도 같이 알려주도록 하겠습니다.

 

만약 문자열을 편하게 사용하려면 스트링 라이브러리를 가져와야 됩니다.

 

#include<string>을 먼저 처음에 써줍니다. 이제부터 string 라이브러리에 있는 내장함수(?)들을 하나씩 알려드리겠습니다.

 

1. strlen(문자열 길이 계산)

 

만약 이 함수를 사용하지 않고 문자열의 길이를 계산한다면 개행 문자가 나올 때까지 이동시키고 계산해주는 코드를 짜야됩니다. 그러나 이 함수를 사용하면 한 번에 문자열 길이를 계산할 수 있습니다. 

 

그림 1

 

이런식으로 strlen(배열이름)을 넣어서 사용하면 됩니다. 그림 1을 보면 알겠지만 jinwoo 총 6글자인걸 잘 알려주고 있습니다.

 

sizeof 함수와의 차이점은 sizeof는 문자열을 저장하는 배열 자체의 길이를 말하고 strlen은 문자열의 길이를 말합니다.

 

그림 2

 

2. strcmp(문자열을 비교하고, 두 문자열의 dictionary 순서를 파악할 때 사용)

 

예를 들어 strcmp(a,b)가 있으면 a가 b보다 나중에 나오면 1을 반환하고, a가 b보다 먼저 나오면 -1을 반환합니다. 그리고 같은 문자열이면 0을 반환합니다.

 

그림 3

 

그림 3에서는 jinwoo가 mandu보다 사전상 앞에 위치하므로 -1이 출력된 것을 알 수 있습니다. 

 

3. strncmp( 정한 글자수만큼만 같은지 확인)

 

strncmp는 strcmp와 다르게 비교할 글자 수를 설정해주는 작업이 필요합니다.

 

그림 4

 

그림 4에 나온 것처럼 비교할 글자수를 정하고 같으면 0,  비교할 값중에서 앞에 값이 사전상 나중에 나오면 1을 반환하고, 반대면 -1을 반환합니다. 

 

4. strcpy(저장할 때 사용)

 

strcpy는 저장할 문자열의 길이를 파악하여 딱 그 길이만큼만 char형 배열에 복사하고, 문자열 끝에 NULL을 자동으로 붙입니다.

 

strcpy(저장될 배열명, 저장할 문자열)로 작성하여 이용합니다.

 

그림 5

 

그런데 오류가 나네요 ㅠㅠ 왜 그럴까요. #define _CRT_SECURE_NO_WARNINGS 이거를 안써서 그렇습니다. 메모리에 접근하는 것이다 보니 이것을 위에 써주면 에러가 안 나게 됩니다.

 

그림 6

strcpy를 이용하면 for문을 사용할 필요없이 스트링을 복사할 수 있게 되어서 훨씬 편하게 이용할 수 있습니다.

반응형
반응형

저번 시간에 이스케이프 시퀀스에 대해서 설명을 했습니다.

 

이번시간에는 랜덤함수에 대해서 배워 보겠습니다.

 

C++을 하면서 랜덤을 쓰는 일은 상당히 많습니다. 이러한 랜덤함수를 이용하려면 라이브러리 2개를 가지고 와야 합니다.

 

첫 번째 라이브러리는 cstdlib로, #include <cstdlib>를 쓰면 rand(), srand()라는 내장 함수를 사용할 수 있습니다.

 

두 번째 라이브러리는 ctime으로 #include <ctime>를 쓰면 time()라는 내장 함수를 사용할 수 있습니다. 이 time()은 랜덤 한 수 출력을 위해 현재시간을 사용하므로 현재시간을 이용할 수 있게 도와주는 함수입니다.

 

이제 이 라이브러리 두 개를 활용해서 랜덤한 수들을 출력해 보겠습니다. 그런데 만약 ctime 라이브러리 없이 난수(랜덤 한 수)를 출력해 보면 어떻게 될까요

 

 

#include<iostream>
#include<cstdlib>

using namespace std;

int main(){
	cout<<rand();
	cout<<rand();
}

 

그림 1

 

몇 번을 해도 난수는 같은 숫자가 나올 것입니다. 왜냐하면 컴퓨터에서 난수생성하는 방식이 정해져 있는데 이러한 고정된 seed값으로 난수를 생성하니까 계속해서 같은 값이 나오게 됩니다. 그렇기 때문에 ctime을 이용해서 무작위 난수를 출력합니다.

 

사실 이것도 무작위라고 보기는 어려워서 최근에는 다른 방식을 쓰는데 다음에 시간 날 때 작성해 보겠습니다.

 

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main()
{
    srand((unsigned int)time(NULL));//씨드값으로 현재시간을 이용
    cout<<rand();
    cout<<rand()%6;// 6으로 나눈 값의 나머지를 출력
}

그림 2

 

위처럼 ctime을 사용하게 되면 time()을 이용할 수 있고, 이 내장함수를 통해 시드값을 넣어서 랜덤 한 수를 뽑아낼 수 있게 하는 srand()를 이용하여 무작위 한 랜덤 수를 뽑아낼 수 있습니다.

 

그리고 %(나머지 연산자)를 활용하여 자신이 최대로 뽑아내고 싶은 값의 한계치를 정할 수 있습니다.

반응형
반응형

저번 시간에는 연산자에 대해서 배웠습니다. 이번 시간에는 escape sequence에 대해서 배워보려고 합니다.

 

이스케이프 시퀀스는 백슬러시(\) 뒤에 한 문자나 숫자 조합이 오는 문자 조합을 이스케이프 시퀀스라고 합니다.

 

이스케이프 시퀀스를 언제쓰냐면 줄 바꿈 문자, 작은 따옴표, 특정 문자들을 나타내려면 이스케이프 시퀀스를 사용합니다.

 

이스케이프 시퀀스는 단일 문자로 간주됩니다.

 

https://learn.microsoft.com/ko-kr/cpp/c-language/escape-sequences?view=msvc-170

 

이스케이프 시퀀스

자세한 정보: 이스케이프 시퀀스

learn.microsoft.com

 자세한 것은 여기서 보면 됩니다. 그리고 이스케이프 시퀀스를 자주 쓰는 문제 하나만 추천해드리겠습니다. 

https://www.acmicpc.net/problem/25083

 

25083번: 새싹

아래 예제와 같이 새싹을 출력하시오.

www.acmicpc.net

 

이 문제를 풀 때 주의해야 되는 건 백슬래시(\\),작은 따옴표(\'), 큰 따옴표(\") 입니다. 이러한 것을 나타낼때는 \를 사용해서 나타내야합니다. 이 밖에도 자주쓰는 \t,\n도 이스케이프 시퀀스입니다.

반응형
반응형

이번시간에는 연산자에 대해서 알아보려고 합니다. 앞시간에 =이 할당연산자라고 배웠습니다. 그러나 당연히 이 밖에도 여러 연산자가 많습니다.
 
일반적으로 우리가 연산을 할 때 어떤 연산자를 많이 쓰나요? 덧셈, 뺄셈, 곱셈 이런것을 많이 씁니다.
 
C++에서도 이 같은 연산을 할 수 있습니다. 
 

1. 산술 연산자

 
곱하기는 *, 더하기는 +, 빼기는 -, 나누기는 /, 나머지 연산은 %입니다. 
 
%같은 경우는 자기가 나눈 값에서 나머지 부분을 출력해줍니다.
 

그림 1

 
그리고 C++에서는 1씩 증가하거나 감소하거나, 증가하는 것을 표현할 때 ++ 또는 --로 나타냅니다.
 

그림 2

 
그런데 ++또는 --를 앞에 붙이냐 뒤에 붙이냐에 따라 전위, 후위라고 부릅니다. 그렇다면 두 개의 차이점이 무엇일까
 
a의 값은 연산이 다 끝난 후에는 전위냐 후위냐를 나누는 것은 의미가 없다. 왜냐하면 값이 같기 때문이다. 
 
그러나 그 값을 출력할 때는 값이 다릅니다.
 
위의 그림 2처럼 a++는 값이 변하기 전 값을 출력하고, 그 다음 a가 출력 될 때 변한 값이 출력된다. 그리고 ++a는 처음부터 값이 변한 후 값을 출력합니다.
 

2. 관계연산자

 
관계연산자는 두 값을 비교하는 연산자입니다. 
 
두 값이 같은지를 물어볼 때는 ==
두 값 중 어느 값이 크거나 같은지를 물어볼 때는 >=,<=
두 값 중 어느 값이 큰지를 물어볼 때는 >,<
두 값이 같지 않음을 물어볼 때는 !=을 사용합니다.
 

3. 논리연산자

 
논리연산자는 true, false를 할 때 많이 사용합니다. 
 
AND연산자는 &&
OR연산자는 ||
NOT연산자는 !입니다.
 
AND하고 OR연산자를 쉽게 설명하자면,
 
1. 기본적으로 AND연산자를 *로 보고, OR연산자를 +로 봅니다.
 
2. 논리 연산에서는
1+0=1,
1+1=1,
0*1=0,
1*1=1
이므로 이걸 기억해두면 좋을 거 같습니다.
 

참고로 C++에서는 true가 1, false가 0입니다.

반응형
반응형

저번 시간에는 배열을 포인터를 이용해서 설명을 했습니다.

https://hanglestocks.tistory.com/64

 

이번 시간에는 저번 시간에 배운 내용에서 조금 더 추가해서 말해보겠습니다.

 

정수나 실수 또는 문자만 배열을 사용하여 나타낼 수 있는 것이 아닙니다. 포인터 변수형을 사용하여 배열로 나타낼 수도 있다. 이 때는 배열안에 주소 값들이 저장되게 됩니다.

 

그림 1

 

이 포인터 배열은 문자열을 처리할 때 자주 사용합니다. 문자형 배열과 메모리 사용 효율에서 차이가 나기 때문입니다.

 

예를 들어 문자형으로 배열을 사용하게 된다면 가장 긴 단어에 맞춰서 배열을 설정해주어야합니다.

 

char Name[3][6]={"jinwoo","minsu"."mandu"} 

 

jinwoo가 6글자니까 이런식으로 이차원 배열을 통해 문자형으로 만들 수 있습니다(x) 이거 안됩니다!!!

 

왜냐하면 끝에 개행 문자가 들어가야되므로 6+1=7 적어도 [3][7]만큼의 배열이 와야됩니다.

 

그러나 포인터 배열을 사용하게 되면 각각의 문자열들은 각각 임의의 메모리에 저장되고, 컴파일러가 알아서 저장시킵니다.

 

char* Name1[6]={"jinwoo","dobu","gogi"}  이게 무슨 뜻이냐면 요런 느낌으로 Name이라는 포인터 변수를 만들고, 여기다가 주소를 한 개씩 넣어주는 것입니다.

 

그림 2

 

그리고 포인터 배열을 이용한 문자열에서 첫번째 문자 'j'의 주소가 Name1[0]의 주소가 됩니다. 즉 이 방식을 쓰면 메모리의 낭비가 없습니다.

반응형
반응형

저번시간에는 포인터를 활용해서 스왑함수를 만드는 것까지 했습니다. 

 

이번 시간에는 포인터를 활용해서 배열을 어떻게 나타내는지에 대해서 설명해보려고 합니다.

 

배열의 각 요소는 주소를 가집니다!!

 

예를 들어서 int의 경우에는 a[0]과 a[1]은 4바이트씩만큼 차이나게 됩니다. double같은 경우에는 8바이트씩 차이나겠죠. 

 

그리고 배열의 이름은 주소입니다. 예를 들어 Name[5[의 배열을 선언했다고 하자. 

 

그러면 Name은 &Name[0]과 같습니다. 즉 그냥 Name만 쓰게 되면 Name 배열의 시작 주소를 가리키게 되는 것입니다.

 

그림 1

 

위의 그림 1을 보면 제대로 이해되었을 것입니다.

그림 2

 

좀 응용해보자면 Name이 주소값이기 때문에 Name을 역참조를 하게 되면 Name[0]의 값이 나오게 됩니다.

 

그리고 +1을 사용해 배열의 그 다음 값을 가리킬 수 있습니다. 

 

그림 3

 

int형의 경우 주소가 4바이트만큼 차이가 난다고 하였으나 +1을 해주면 기존 주소 값에 4바이트(int의 경우)를 더해주게 됩니다.

 

반응형
반응형

이번시간에는 포인터를 활용해서 변수의 값을 서로 바꿔주는 과정을 하려고 합니다.

 

일반적으로 포인터 없이 스왑을 한다면 temp를 이용해서 스왑을 하게 됩니다. 포인터를 사용하지 않은 코드는 다음과 같이 짤 수 있습니다.

 

그림 1

 

그러나 만약 함수를 사용하게 된다면 문제가 발생합니다. 1주차에 배웠던 지역변수라는 개념 때문에 원하는 대로 스왑이 되지 않게 됩니다.

 

그림 2

 

함수 안의 지역변수인 a, b는 함수 밖에 있는 num1과 num2에 영향을 주지 못하고 메모리를 반환하게 됩니다. 그렇게 되면 스왑을 제대로 할 수 없습니다.

 

만약 이 때 포인터를 써주게 된다면 이러한 문제를 해결 할 수 있습니다.

 

그림 3

 

이처럼 num1과 num2의 주소값을 스왑함수에 넘겨주고, 역참조를 통해서 스왑스키면 원하는 대로 숫자를 서로 스왑할 수 있습니다.

반응형

+ Recent posts