백터 사용 시 실수 할 수 있는 문제입니다.

 

아래 코드에서 어떤 문제점이 있나 한번 보실래요?

 

#include "stdafx.h"
#include <string>
#include <vector>

using namespace std;

int fn1(vector<string> *pvt) {

	int totallen = 0;
	
	for (int i = 0; i < pvt->size(); i++) {
		totallen += pvt[i].size();
	}
	
	return totallen;
}

int main()
{
	vector<string> vtDumy;
	vtDumy.push_back("hello");
	vtDumy.push_back("my");
	vtDumy.push_back("name");
	vtDumy.push_back("is");
	vtDumy.push_back("ososoi!");

	int totallen = fn1(&vtDumy);

	printf("total len=%d\n", totallen);

	getchar();
    return 0;
}

 

 

위 코드를 가지고 visual studio 에서 빌드하면 정상적으로 빌드가 되고 실행도 됩니다. 

 

우리가 예상한 결과값은 "hellomynameisososoi!" 총 20자 입니다.  

 

하지만 실행하게 되면 

 

오잉 쓰레기값이??

 

결과를 말씀드리면 아래코드에서 문제가 있습니다.

 

totallen _= pvt[i].size();

 

여기서 pvt는 백터의 포인터이기 때문에 실제 우리가 원하는 백터의 n번째 원소(string)의 길이를 얻기위해서는

 

totallen += (*pvt)[i].size();

 

더 명시적으로 표현하자면 아래와 같습니다.

 

totallen += (*(vector<string>*) pvt)[i].size();

 

 

비단 벡터 뿐만 아니라 포인터를 다루면서 종종 실수 할 수 있는 경우인데요,

 

기본 변수 타입의 포인터는 익숙해서 실수를 잘 안 할 수 있는데, 벡터등 컨터이너에 포인터를 붙일 때 . 찍고 컴파일 오류가 없기 때문에 그냥 지나칠 수 있을 것 같습니다.

 

저도 좀전에 실수 해서 생각 나는 김에 여기에 샘플코드와 함께 적어봤습니다. 

 

 

코딩량이 많고 빨리빨리 작업하다보면 빌드가 정상적으로 되는 것을 보고 그냥 지나칠 수 있는데요,

 

잘못하다간 나중에 로직에러 / 데이터 검증에 디버깅 할때는 더 많은 수고가 들지도 모르겠죠..;;

 

포인터를 다룰 때는 함수의 전달과 사용되는 부분들을 꼼꼼히 훑어 보고 다음 코드로 넘어가는 습관과 펑션을 짜고 나서 데이터 전달. 연산에 대한 테스팅을 한번씩 해보고 다음 단계로 넘어가는 습관이 중요할 것 같습니다.

 

 

 

가끔씩 s1 -> s2 인지 s2 -> s1인지 헷갈릴 때가 있다.. 

 

필요한 헤더 : <string.h>

1
2
3
4
5
6
7
//! @brief s2의 문자열을 s1로 복사한다
char *strcpy( char *s1, const char *s2 );
 
//! @brief s2의 문자열을 count(문자갯수)만큼 s1로 복사한다
char *strncpy( char *s1, const char *s2, size_t count );
 
 
cs

 

char *strncpy( char *s1, const char *s2, size_t count );

 - dest에 대한 공간을 확인 하지 않기 때문에 버퍼오버런(buffer overruns) 방지하도록 유의

 - s2에서 null 문자를 만나면, count개의 문자가 쓰여질때까지 s1에 null 문자가 추가된다.

 

번외편. lib을 만들거나 로우레벨 코딩을 할 때 가끔씩 memcpy 쓸때가 있다. 

 

1
2
//! @breif s2의 문자열을 s1으로 n개 만큼 복사한다
void *memcpy(void *s1, const void *s2, size_t n);
cs

그럼 strncpy 와 memcpy 가 하는 일은 같다. 호기심이 생기지 않는가. 직접 속도차이가 궁금하여 테스트 코드를 돌려보았는데 1000바이트의 문자열을 1억번 단순 복사 하는 프로그램이다. 수회 돌려 본 결과 

결과는

평균적으로 strcpy가 2초, memcpy는 1초가 채 안된다.

아래는 짜본 테스트코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "stdafx.h"
#include <string.h>
#include <time.h>
 
int main()
{
    char s1[1024];
    char s2[] =
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" \
        ;
 
    time_t t1, t2 ,t3;
 
 
    t1 = time(NULL);
    for (int i = 0; i < 100000000; i++)
    {
        memcpy(s1, s2, sizeof(s2));
    }
    t2 = time(NULL);
 
    for (int i = 0; i < 100000000; i++)
    {
        strncpy(s1, s2, sizeof(s2));
    }
    t3 = time(NULL);
 
    printf("strcpy:%u, memcpy:%u\n", t2 - t1, t3 - t2);
 
    getchar();
    return 0;
}
 
cs

 

strncpy vs memcpy 에 대해서 다음에 좀더 이야기를 해보도록 하겠습니다.

 

ps - 위 테스트 코드들에서는 변수 초기값을 할당 하지 않았지만 항상 초기값을 세팅하는 습관이 아주 중요하다고 입이 닳고 마르도록 얘기하고 싶습니다.

 

'까벨로퍼 > 개발 이야기' 카테고리의 다른 글

[Linux/Unix] Tcpdump(2)  (0) 2020.06.29
[Linux/Unix] Tcpdump  (0) 2020.06.29
[Xcode] 단축키 모음  (0) 2020.06.26
[c#] 프로그램에 아이콘 집어넣기  (0) 2020.06.24
[Linux/Unix] iptables 설정  (0) 2020.06.24

+ Recent posts