JC Tailor

블로그 이미지
컴퓨터를 사랑하자.~
dkcjs3

Article Category

분류 전체보기 (52)
프로그램방법론 (0)
Tailor 이야기 (0)
C언어 이야기 (49)
C++ 이야기 (1)
API 이야기 (0)
MFC 이야기 (0)
Window XP 이야기 (0)
컴퓨터정보 (1)
나의 삶 이야기 (1)
UNIX (0)

Recent Comment

Recent Trackback

Calendar

«   2007/07   »
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        

Archive

  • Total24,658
  • Today0
  • Yesterday6
  1. 2007.07.31
    void와 void*(포인트)
  2. 2007.07.31
    문자열 변환 함수 atoi() 구현
  3. 2007.07.31
    strcpy(), strncpy(), strdup()함수 ~ (1)
  4. 2007.07.31
    1. strcpy(...)2. strcat(...)3. strcmp(..)에 관하여 ...
void와 void*(포인트)
void와 void*(포인트)

1. void

   주1)에서와 같이 void는 비어있다 아무것도 없다는 뜻을 가지는 단어이다. void가 단독으로 사용되는 경우에는 사전적인 의미에서와 같이 "아무것도 없다"로 사용된다.

   - 함수의 인자로 사용

      예1)  함수 선언 : int GetValue( void );

     즉, 입력되는 것이 없다.     

  - 함수의 리턴값으로 사용

      예2) 함수 선언 : void SetValue( int nValue );

     즉, 리턴되는 값이 없다. 비주얼 베이직에서  Sub와 동일하다.


2. void*(포인트)

  void*는 void와 다른 의미를 가진다. void*는 "어떤것이라도 가르킬 수 있다"로 사용된다.

   예3)

       float fValue = 0.0f;

       short nValue = 0;

       short* pnValue = &nValue; // short형 포인트

       float* pfValue = &fValue; // float형 포인트

      void* pValue = ( void* ) &nValue; // short형 포인트(주소)를 void*포인트에 할당

      pValue = ( void* ) &fValue; // float형 포인트(주소)를 void*포인트에 할당

     pfValue = ( float* ) pValue; // pValue는 float형 포인트를 가르키고 있기 때문에 문제가 없다.

     pnValue = ( short* ) pValue; // 컴파일 오류(경고 포함)는 생기지 않지만, 포인트(pValue)가 가르키는 데이타형이 틀리기 때문에 심각한 문제가 발생할 수 있다.

  예3)에서와 같이 void*는 무엇이든 할당할 수 있다. 컴파일러에 따라 틀리지만, 형변환은 반드시 해야 한다.      


3. void*는 무엇이든 할당할 수 있다는 점이 강력한 장점이지만, 심각한 문제를 발생시키는 원인

    예4)

     short nValue[ 10 ];

     float* pfValue = NULL;

     void* pValue = NULL;

     pValue = &nValue;

     pfValue = ( float* ) pValue;

 예4)에서와 같이 pValue를 강제로  pfValue에 할당을 할 경우에 심각한 문제가 생길 수 있다.

시스템 혹은 운영체제에 따라 틀리지만, short는 2바이트, float는 4바이트의 데이타형이다. 위와 같이  pfValue를 사용하게 되면, pfValue[ 5 ]부터 short nValue[ 10 ]에 할당된 메모리 영역을 벗어 나게 된다. 벗어난 메모리 영역에 값을 쓰게 되면 어떤 현상이 생길지는 아무도 모른다. 아무도 모른다는것이 가장 큰 문제이다. 특히, 벗어난 영역이 다른 값을 침범하게 된다면, pfValue를 사용하지 않는 멀쩡한 코드에서 갑자기 오류가 생겨 디버깅이 힘들어지는 경우도 생긴다. 물론, 예4)에서와 같이 할당하는 프로그래머는 없겠지만, 유사한 형태는 나올 수 있다.


주1) void 뜻 : http://endic.naver.com/endic.nhn?docid=1254810

신고
Trackback 0 and Comment 0

문자열 변환 함수 atoi() 구현

 

1. atoi()의 함수에 대하여

- 함수원형 : int atoi(const char *s);       /* ascii to integer */

  - 헤더파일 : stdilb.h

  - 기능 : 문자열을 정수로 변환한다. 문자열은 숫자 및 부호로 이루어져 있어야 하며 앞부분에 TAB 이나 공백이 있어도 상관없다. 그러나 영문자, 불필요한 기호 등이 있을 때는 변환이 중지 된다. Overflow에 대한 에러처리는 하지 않는다. 만약 int형의 범위를 넘는 수가 문자열에 들어있을 경우 65536으로 나눈 나머지를 리턴한다.

- 리턴값 : 문자열로부터 변환된 정수, 변환이 불가능한 경우 0이 리턴된다.

 

2. 소스코드

int atoi(char *st)

{

        int i = 0, j = 0;

 

        if (*st == '-' || isdigit(*st)) {

                if(*st == '-') j = 1, st++;

                while(isdigit(*st))

                {

                        i = i * 10 + (*(st)) - 48;

                        st++;

                }

                if (j == 1) return -i;

                else return i;

        }

        else

                return 0;

}

 

3. 실행결과

dalma[ahriman{85}  ~ ] a.out

atoi함수 구현

input : 12341

output : 12341

dalma[ahriman{86}  ~ ] a.out

atoi함수 구현

input : -123123

output : -123123

dalma[ahriman{87}  ~ ] a.out

atoi함수 구현

input : -123.21312

output : -123

dalma[ahriman{88}  ~ ] a.out

atoi함수 구현

input : 34lkd2312

output : 34

신고
Trackback 0 and Comment 0

strcpy함수는 전체 문자열을 다른 메모리 영역으로 복사한다.


*함수 원형


char *strcpy(char *복사시킬 문자열, char *원래 문자열);


복사시킬 새로운 문자열의 포인터를 돌려준다.



/*'strcpy'의 사용 예*/

#include
#include
#include

char source[]="The source string.";

int main()
{
    char dest1[80];
    char *dest2, *dest3;
   
    printf("source : %s", source);
   
    /*dest1이 80바이트의 할당된 공간을 지적하므로*/
    /*dest1로의 복사는 정상적이다.*/
   
    strcpy(dest1, source);
    printf("\ndest2 :  %s", dest1);
    
    /*dest2로 복사하기 위해서 공간을 할당해야 한다.*/
   
    dest2 = (char*)malloc(strlen(source)+1);
    strcpy(dest2, source);
    printf("\ndest2 :  %s", dest2);
   
    /*대상 공간을 할당하지 않고 복사하는 것은 좋지 않다.
    다음은 심각한 문제를 일으킬 수 있다.*/
   
    /*strcpy(dest3, source);*/
   
    getchar();
   
     return 0 ;

}



strncpy함수는 복사할 문자의 개수를 지정할 수 있다.


*함수 원형


char strncpy(char *복사시킬 문자열, char *원래 문자열, size_t 개수);


역시 복사시킬 문자열의 포인터를 돌려준다.


/*'strncpy'의 사용 예*/

#include
#include

char *dest = "..........................";
char *source = "abcdefghijklmnopqrstuvwxyz";

int main()
{
    size_t n;
   
    while(1)
    {
        puts("Enter the number of characters to copy (1-26)");
        scanf("%d", &n);
       
        if(n>0 && n<27) break;
       
    }
   
    printf("\nBefore strncpy destination = %s", dest);
   
    strncpy(dest, source, n);
   
    printf("\nAfter strncpy destination = %s", dest);
   
    getchar();
   
    return 0;
   
}


.. 이 소스는 될런지 모르겠다.

분명 정확히! 적었는데 아무리 해도 되지를 않고

디버그를 해봐도 segmentation fault로 나와 고생고생 쌩난리를 쳐도 안되더라(..)


결국 마음속으로 '컴파일러가 이상한거야, 그런거야!'를 되풀이하며 묻어버렸다.(...)

에러만 나면 무조건 컴파일러의 탓만 하는 안좋은 습관이 생겼다.OTL


strdup은 알아서 malloc()함수를 호출하여 목적 문자열을 저장하기 위한 메모리 영역을 할당한다.


char *strdup(char *source);


strdup은 목적 문자열에 대한 포인터를 돌려준다.

strdup은 ANSI 표준 함수가 아니다! (그런데도 잘만 되더라,)


/*'strdup'의 사용 예*/
#include
#include
#include

char *source = "The source string";

main()
{
    char *dest;
   
    printf("Source = %s", source);
   
    if((dest = strdup(source)) == NULL){
        fprintf(stderr, "Error allocating memory.");
        exit(1);
    }
   
    printf("\nDestination = %s", dest);
   
    getchar();
   
    return 0;
}


strlib에 있는 exit함수는

'닭치고 종료'의 기능을 한다.

인수가 0이면 '정상 종료'를,

1이면 '비정상적인 종료'를 의미한다.


맨 끝의 getchar은

dev C++에선 Visual C++와는 달리 실행 파일에 'Press any key to continue'따위가 나오지 않고

출력 하자마자 볼 새도 없이 곧장 꺼져버버리길래, 그냥 확인용으로.

Visual C++에선 쓸 필요가 없는 녀석.

신고
Trackback 0 and Comment 1

/*
Q: strcpy 이거에 대한 건데요 ..
   a가 abc이고 b가 def인데 a와 b를 strcpy하고
   a를 출력하면 def가 나와야 하는거에요
   abcdef가 나와야 하는거에요?

A: def가 나와야합니다. 아래 1의 strcpy(...)를 참고하세요

우선 string.h에 있는 함수들에 대한 설명입니다.

1. strcpy(...)
  원형( prototype ) :
      char *strcpy(char *dest, const char *src);

  설명 : src가 지시하는 문자열을 dest라는 포인터가 지시하는 공간에 복사하고
              그 결과 문자열 dest을 리턴합니다..

  예 : char newstr[32];
          char oldstr[] = "coffee";
          strcpy( newstr, oldstr );


  결과 : newstr -> "coffee"

2. strcat(...)
   원형( prototype )
      char *strcat(char *dest, const char *src);

  설명 : src가 지시하는 문자열(src 문자열 )을 dest가 지시하는 문자열의
              끝에 덧 붙이고 결과를 리턴합니다.

  예 : char str1[] = "abc";
          char str2[] = "def";
          strcat( str1, str2 );


  결과 : str1 -> "abcdef"

3. strcmp(..)
  원형( prototype)
      int strcmp(const char *s1, const char *s2);

  설명 : 문자열 s1과 s2를 사전식( 오름차순 )으로 비교하여 결과를 리턴합니다.
  예 : char str1[] = "big";
         char str2[] = "bigger";
         int result;
         result = strcmp( str1, str2 );

         result 가 0 이면 str1과 str2가 같은 문자열
         result가 양수이면 str1이 str2보다 크다 ( str1이 str2의 뒤에 위치 )
         result가 음수이면 str1이 str2보다 작다 ( str1이 str2보다 앞선다 )

        "big"과 "bigger"의 비교
         "big"  "bigger"
         'b'        'b'
         'i'          'i'
         'g'        'g'
        '\0'        'g'

        최초로 일치하지 아니하는 문자의 차(difference)를 strcmp의 결과로 리턴합니다.
        '\0' - 'g' => 0 - 103 = -103를 리턴
*/


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

/*
사용자가 정의함수( user defined function )
함수의 원형( 프로토 타입 = prototype )을 선언합니다.


표준함수와 구별하기 위하여 앞에 "my"라는 접두어를 붙였습니다.
파라메타의 형에 const라는 modifier(수정자)를 붙인 것은 함수를 정의할 때
문자열을 수정하지 않는다는 의미입니다. */


/* 문자열 복사함수 */
char* mystrcpy( char* dest, const char* src );

/* 문자열 덧붙이기 함수 */
char* mystrcat( char* dest, const char* src );

/* 문자열 비교함수 */
int mystrcmp( const char* s1, const char* s2 );

int main(void)
{
   /* 두개의 문자배열을 선언 */
   char first[255], second[255], copy[255];
   int query, result;

   printf( "두개의 문자열을 입력하여 \n함수 mystrcat(..과 mystrcmp(..를 테스트합니다.\n" );
   while( 1 )
   {
      printf( "\n첫번째 문자열 >> " );
      scanf( "%s", first );
      fflush( stdin );

      printf( "두번째 문자열 >> " );
      scanf( "%s", second );
      fflush( stdin );

      /* 복사 테스트 - mystrcpy */
      mystrcpy( copy, first );
      printf( "복사된 첫번째 문자열은 %s입니다.\n", first );
      mystrcpy( copy, second );
      printf( "복사된 두번째 문자열은 %s입니다.\n", second );
      system( "pause" );

      /* 비교 테스트 - mystrcmp */
      result = mystrcmp( first, second );
      printf( "\n" );
      if( result == 0 )
        printf( "두 문자열 %s와 %s는 같은 문자열입니다\n", first, second );
      else if( result < 0 )
        printf( "문자열 %s는 문자열 %s보다 앞 섭니다\n", first, second );
      else
        printf( "문자열 %s는 문자열 %s의 뒤에 위치합니다\n", first, second );
      system( "pause" );

      /* 덧붙이기 테스트  - mystrcat */
      printf( "\n문자열 %s에 ", first );
      mystrcat( first, second );
      printf( "%s를 덧 붙이면 문자열 %s가 생성됩니다.\n", second, first );

      printf( "\n종료하시려면 'Q'나 'q'를 계속하시려면 그 밖의 아무 키나 누르세요 >> " );
      query = getchar();

      if( query == (int)'Q' || query == (int)'q' )
      {
         printf( "프로그램을 종료합니다\n" );
         break;
      }
   }
   return 0;
}

char* mystrcpy( char* dest, const char* src )
{
     int i = 0, j = 0;

       /*
      src 문자열의 요소문자(src[i])가
      끝의 널문자('\0')에 도달하지 아니한 동안 복사합니다.*/

      while( src[i] != '\0' )
          dest[j++] = src[i++];
      dest[j] = '\0';

      return dest;

       /*
       // 보다 빠른 소스
       // dest라는 포인터는 유지하고
       // p에 dest를 저장한 후 p를 이동하면서 조작

       char* p = dest;
       while( *src )
           *p++ = *src++;
       *p = '\0';

       return dest;
     */

}

char* mystrcat( char* dest, const char* src )
{
   int i = 0, j = 0;
   char* p = dest;

   while( p[i] != '\0' ) i++;
   while( src[j] != '\0' )
      p[i++] = src[j++];
   p[i] = '\0';

   return dest;

  /*
  // 보다 빠른 소스
  // dest라는 포인터는 유지하고
  // p에 dest를 저장한 후 p를 이동하면서 조작


  char* p = dest;


  /* 포인터를 문자열 dest의 끝으로 이동시킵니다. */
  while( *p ) p++;
  while( *src )
          *p++ = *src++;
  *p = '\0';

  return dest;
  */
}

int mystrcmp( const char* s1, const char* s2 )
{
   
/*
   s1이 지시하는 문자가 널문자가 아닌 동안 비교
   s2가 지시하는 문자가 널문자인 경우는 아래 if문에서 catch됩니다. */


   while( *s1 )
   {
      if( *s1 != *s2 )
         break;
      s1++;
      s2++;
   }
   return (*s1 - *s2);
}
   

신고
Trackback 0 and Comment 0

Tag Cloud


티스토리 툴바