«   2026/02   »
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

atoi : Alphabet TO Integer

itoa : Integer TO Alphabet


두 함수의 사용에 대해 포스팅을 하고자 한다.

나 또한 C가 익숙하게 사용할 수준이 아니기 때문에 사소하거나 쉬운 것조차 자주 헷갈리거나 까먹어 구글링을 하고는 한다.

그런데 정말 정말 정말.. itoa 부분에 대해 사람들이 잘 모르거나 심지어 욕설까지 하는 경우까지 있다.

이유는 C를 가르칠 때, 이것이 표준인지 아닌지를 가르쳐주지 않기 때문에 발생한다.

적어도 국내에서 많은 학교나 학원, 코딩과외 등에서 Visual Studio로 교육을 하는데 강의를 들을 때도, 보조강사로 일해볼 때도 한번도 표준과 비표준을 가르쳐주는 강좌가 없었다. 


"숫자에서 문자열로 바꾸려면 itoa를 쓰시면 되어요."


이게 끝이라는 것이다.


결론부터 말하자면 itoa는 표준이 아니다. 비표준이다.

비표준 함수를 다른 환경에서 사용을 하고, 안된다고 욕설을 하는 경우를 자주 보게 된다.

나는 주변에 내 주도하에 프로그래밍을 가르쳐줄 때, 이런 부분 때문에 내가 몰라서 못 가르쳐준 것이 아니라면 이것이 표준인지 비표준인지를 확실히 하고 가르친다.

그 순간에 이해를 못하더라도, 한두번이라도 들어두면 다음에 그만큼 삽질과 잘못된 이해를 바로잡을 수 있다.


먼저, itoa는 Visual Studio에서 "임의로 stdlib.h에 입력한 함수다!"


최신 C표준은 내가 알지 못하기 때문에 최신 표준에서 추가가 되었다면 알려주시면 감사합니다.

C18에서는 추가가 되었다는 소식입니다.

하지만 실 개발환경에 전부 적용되려면 수 년은 지나야 할 것입니다.

거기에 제가 알기론 itoa 등은 Borland C(지금의 Embarcadero..)의 함수로 알고 있어서 쉽게 표준에 들어갈 수 없는 것으로 알고 있는데..


그러나, 대부분의 표준 c 환경에서는(c++과의 호환에도 문제가 없는) stdlib.h에 itoa는 없다.

생각을 해보자.

동일 버전의 표준 C 라면, 그것이 리눅스가 되었든 유닉스가 되었든 맥이든 윈도우든 다 사용이 가능해야 표준 아닐까?

윈도우에서는 되는데 리눅스에는 안된다고 욕설을 종종 보는데, 애초에 그것이 비표준이라는 생각을 해볼 수 있지 않을까?

이는 처음 배울 때 표준과 비표준의 개념을 가르쳐주지 않는 대부분 교육 실태의 문제라고 본다.

아직 모르니까, 처음이니까 라는 핑계로 건너뛰는 경우가 많은데, 그럴수록 확실히 짚고 넘어갈 것은 넘어가야 한다.

위 개념을 모르니까 "비표준일 것이다" 라는 생각에 도달할 수가 없는 것이다.


atoi는 표준이 맞으며 어떤 환경에서도 동작하지만

itoa는 비표준이므로 어떤 환경에서도 동작을 보장할 수 없다.


itoa를 사용하려면 본인이 별도로 함수를 만들어 써야하는데 다음과 같이 쉽게 전환이 가능하다.

리는 다른 타입의 역순 전환도 해당된다.

다만 임의로 편리하게 작성한 것이므로 충분한 버퍼 크기를 정해줘야 하며, 이에 따른 순간의 메모리 손실은 어쩔 수 없다.


아래에는 쉽게 변환하는 부분과, 메모리 손실을 최소화 하는 방법을 기술하였다.


간단한 방법(수정 2018.02.12)

char * ftoa(float f) {

char buf[256];

char *buf;

sprintf(buf, "%f", f);

return buf;

}


char * itoa(int i) {

char buf[11];

char *buf;

sprintf(buf, "%d", i);

return buf;

}


제보받은 C18에서의 ftoa(사실 검증이 필요하다.)

void ftoa (float fval, char *buf, int nField, int nPlaces) 

 { 

 //Formats a floating point number into it's ASCII representation.

 // Emulates %[w].[p]f in printf format statements for those using C18 which does support %f

 // Input:

 // fval the float to be converted to ASCII

 // buf a char array to contain the return string

 // nField total width of resulting field. Equivalent to the [width] field of printf

 // nPlaces width of fractional part. Equivalent to the [precision] field of printf

 // Output:

 // buf Null terminated formatted string

 //

 // e.g ftoa(12.3456789,&buf,10,5); will produce buf  containing '  12.34567'

 // 

  sprintf (buf,"%*d.%0*lu", nField-nPlaces-1, (int) fval, nPlaces, (long int) ((fval - (int) fval ) * pow(10, nPlaces)) ); 

 }


,

요즘 심심해서 관리를 대신 해주는 지인 서버에 반 자동화 프로그램을 만들고 있다.

이 서버는 여러 하드디스크가 있는데 용도에 맞게 각 하드에 디렉토리를 생성 -> 새 사용자를 추가하고 권한 위임와 공유, 마운트 지점까지 모든 작업을 수작업으로 하려면 조금 귀찮은데-특히 한명이 아니라면-이를 프로그램으로 짜 넣어 아이디와 비밀번호만 입력하면 미리 지정된 옵션대로 자동으로 되도록 하려고 한다.


파일질라의 암호화 방식이 md5여서 파일질라의 반자동화 프로그램을 만들기 위해선 md5의 알고리즘 프로그램이 필요한데 유명한 알고리즘인 만큼 인터넷에 이미 공개된 샘플이 있을 거라 생각하였다.

구글링을 해보니 RSA Data Security에서 1990년도에 발행한 샘플 코드가 있었는데 여기에서 내게 필요한 것 외에 또다른 나의 궁금증을 해결할 수 있었다.


이 프로그램에서는 별도의 메인 동작은 없지만 입력받은 argv 내용에 따라 동작이 달리하게끔 되어있는데

-s암호내용 을 입력하면 

-s를 떼버리고 남은 내용을 함수로 전달하는 간단한 방법이었다.

이런 간단한 걸 내가 너무 돌아가서 생각했다니 부끄러울 따름..


for (i = 1; i < argc; i++)

      if (argv[i][0] == '-' && argv[i][1] == 's')

        MDString (argv[i] + 2);

      else if (strcmp (argv[i], "-t") == 0)

        MDTimeTrial ();

      else if (strcmp (argv[i], "-x") == 0)

        MDTestSuite ();

      else MDFile (argv[i]);


다만 이 방법에서 궁금한 것은 각 동작이 입력받은 순차적으로는 동작하는 것 같지만 동시에 복합적으로는 안되는 것으로 보인다.

아무래도 복합적으로 동작하게 하려면 좀 더 복잡해야겠지.


혹시나 md5 예제 때문에 방문했다면 아래의 블로그를 확인해 받아가기를 바란다.


원문은 아니지만 http://yegam400.tistory.com/97 에서 원 소스를 보기 좋게 md5.h md5.c md5drive.c 로 나누어 주었다.

md5.h, md5.c가 중요하며 md5drive.c는 두 파일을 이용하여 실제 동작을 만들어 내기 위한 함수일 뿐 다른 프로그램에 이식하려면 저 두 가지만 있으면 될거라고 본다.

Visual C++ 6.0에서 만들었다고 해서 식겁했지만.. 뭐 다행히도 2013기준으로 상위버전으로 호환은 문제 없이 되었다.

(종종 너무 구버전에서 나온 프로젝트면 최신 버전에서 호환이 안되는 문제가 있기에..)

,

c 프로그래밍 연습용으로 만들어보던 프로그램 중 하나입니다.

프로그램과 동일 경로에 폴더를 만들고 비밀번호를 걸어 숨기고 보이고 하게끔 하는 기능입니다.

라곤 하나 아직 배울게 많아 파일 구조나 그런 난이도 있는 쪽으로 접근한건 아니고 임시용으로 디렉토리에 속성만 가했습니다.

아주 기본적인 방법으로 만들었을 뿐이고 때문에 보호된 운영체제 파일 보기에 체크가 되어 있으면 보이긴 하며 정확한 경로명을 알아내면 패스워드 없이도 접근은 됩니다.

알고리즘을 적용하는 방법을 몰라 비밀번호는 소스 내에 포함하도록 하였습니다.


예시 프로그램 : 

secfol1.exe

#일부 환경에서 MSVCR110.dll 누락으로 프로그램이 실행되지 않는 문제가 있습니다.(XP에서는 넣어줘도 실행이 안됩니다)

#해당 환경 이용자는 직접 컴파일 하시는걸 추천드립니다.


코드 :

#include <stdio.h>

#include <Windows.h>

#include <direct.h>

#include <io.h>

#define SECDIR "Control Panel.{21EC2020-3AEA-1069-A2DD-08002B30309D}"

#define DIR "locked"

#define PASSWORD "123456789"

#define PASS_SIZE 16

#define LOCK 1

#define UNLOCK 0

#define CMD_LEN 256

void lock();

void unlock();

void md_dir();


int status;

char dir[CMD_LEN];

char secdir[CMD_LEN];

char password[PASS_SIZE]=PASSWORD;


void main(){

char pass[CMD_LEN],cho;

if(_access(SECDIR,00)==-1)

if(_access(DIR,00)==-1)

{md_dir();status=UNLOCK;}

else status=UNLOCK;

else status=LOCK;


if(status==UNLOCK){

printf("Are you sure you want to lock the folder(Y/N)\ncho=>");

scanf_s("%c",&cho,2);

if(cho=='Y'||cho=='y')

lock();

else exit(1);

}else{

printf("Enter password to unlock folder : ");

scanf_s("%s",pass,PASS_SIZE);

if(strcmp(pass,password)==0) unlock();

else printf("Invalid password\n");

}

//printf("password = %s\n",PASSWORD);

system("pause");

}


void md_dir(){

_mkdir(DIR);

printf(DIR);printf(" created successfully\n");

}


void lock(){

char cmd[CMD_LEN];

strcpy_s(cmd,CMD_LEN,"ren ");

strcat_s(cmd,CMD_LEN,DIR);

strcat_s(cmd,CMD_LEN," \"");

strcat_s(cmd,CMD_LEN,SECDIR);

strcat_s(cmd,CMD_LEN,"\"");

//system(cmd);

system(cmd);

strcpy_s(cmd,CMD_LEN,"attrib +h +s \"");

strcat_s(cmd,CMD_LEN,SECDIR);

strcat_s(cmd,CMD_LEN,"\"");

system(cmd);

printf("Folder Unlocked successfully\n");

}


void unlock(){

char cmd[CMD_LEN];

strcpy_s(cmd,CMD_LEN,"attrib -h -s \"");

strcat_s(cmd,CMD_LEN,SECDIR);

strcat_s(cmd,CMD_LEN,"\"");

system(cmd);

strcpy_s(cmd,CMD_LEN,"ren \"");

strcat_s(cmd,CMD_LEN,SECDIR);

strcat_s(cmd,CMD_LEN,"\" ");

strcat_s(cmd,CMD_LEN,DIR);

system(cmd);

printf("Folder Unlocked successfully\n");

}


,

출처 : http://itguru.tistory.com/36


게시글 삭제 혹은 블로그 폐쇠 방지를 위해 해당 부분만 스크랩.


 scanf 함수의 고질적인 문제 및 해결책
 

scanf 함수를 사용하다 보면 다음과 같이 입력을 받지 않고 넘어가는 경우가 종종 있다.

    printf("숫자를 입력하세요 : ");
    scanf("%d", &num);

    printf("문자를 입력하세요 : ");
    scanf("%c", &c);

로 하면 "문자를 입력하세요 : " 부분이 실행되지 않고 넘어간다. 
이러한 일이 발생하는 원인과 해결책은 여기를 누르면 알 수 있다. 이 글에 제시된 해결책 보다 조금 높은 수준을 원한다면 * 문자를 활용하면 된다. 앞에서 말했듯이 * 문자는 stdin 에서 입력은 받지만 그 데이터는 버려버리는 특징을 이용하면

scanf("%d", &num);
scanf("%*c%c", &c);

와 같이 하면 된다. 왜냐하면 "%*c%c" 라는 형식 문자열의 의미는 "stdin 에서 한 문자를 얻어오되 그 값은 버리고 (이 경우 \n 이 버려진다), 그 다음에 한 문자를 얻어와 이에 대응되는 인자 (&c) 에 저장한다" 이기 때문이다. 

하지만 이러한 문제를 가장 잘 해결하는 방법은 fgets 함수를 이용하는 것이다. 

  scanf 함수 사용시 주의할 점
 

scanf 함수는 문자열 입력시 입력받을 문자열의 최대 개수를 제한을 두지 않으므로 버퍼 오버플로우가 발생할 여지가 충분히 있다. 이를 해결하기 위해서는 역시 fgets 함수를 이용하거나 폭을 지정해 주면 된다. 예를 들어서

char str[10];
scanf("%9s", str);

와 같이 한다면 우리가 stdin 에 아무리 많이 입력해도 scanf 는 오직 9 문자만을 취하므로 안전하게 입력이 가능하다. (배열의 크기는 10 이지만 NULL 문자를 위해서 9 자만 입력해야 한다) 하지만 이와 같이 할 경우에도 문제가 있는데, 사용자가 9 문자 보다 많이 입력했을 경우 scanf 는 오직 9 문자만을 처리하므로 일부 문자가 버퍼에 남아 있어서 다음번 입력 시 차질이 생긴다. 이는 다음과 같이 해결 할 수 있다.

scanf("%9s%*s", str);

왜냐하면 처음 %9s 를 통해서 9 문자만 입력 받고 stdin 에 남아있는 나머지 문자열들은 %*s 가 날려버리기 때문이다. 

  실행 예제
 

/* 각 형식에 맞는 입력을 받은 뒤 이를 출력한다.*/
#include <stdio.h>
int main()
{
    char str[10];
    char ch;
    int dec, hex, oct;
    float db;

    printf("문자열, 문자, 십진수, 16 진수, 8 진수, 소수를 각각 입력하세요\n");
    scanf("%9s %*s %c %d %x %o %f", str, &ch, &dec, &hex, &oct, &db);

    printf("문자열 : %s \n", str);
    printf("문자 : %c \n", ch);
    printf("십진수 : %d \n", dec);
    printf("16 진수 : %x \n", hex);
    printf("8 진수 : %o \n", oct);
    printf("소수 : %f \n", db);
    return 0;
}

실행 결과


,

아는 동생의 부탁으로 묵찌빠 로직을 만들었는데, 이것을 같이 공유해 처음 공부하는 다른 학생들도 참고해서 이런 방법도 있다 정도로 알아뒀으면 좋겠다.


간단한 예시로 빈도분석과 같은 로직은 추가하지 않았다.



#include <stdio.h>

#include <stdlib.h>

#include <time.h>


int main (){

int win=0;//승리수

int me;//유저

unsigned int rand_num;

srand((unsigned int)time(NULL));


while(1){

printf("묵찌빠를 시작하기 전에 선을 정하기 위하여 가위바위보를 해야합니다.\n다음 메뉴중 원하는것을 입력해주세요.\n\n메뉴번호[1=가위 2=바위 3=보] : ");

scanf("%d",&me);//처음 가위바위보 값

rand_num=rand()%(3)+1;


if(me==1){

printf("당신은 가위를 내셨습니다. 컴퓨터는 ");

if(rand_num==1) printf("가위를 냈습니다. 그 결과 비겼습니다.\n");

if(rand_num==2) printf("바위를 냈습니다. 그 결과 졌습니다.\n");

if(rand_num==3) {printf("보를 냈습니다. 그 결과 이겼습니다.\n");win++;break;}

}


if(me==2){

printf("당신은 바위를 내셨습니다. 컴퓨터는 ");

if(rand_num==1) {printf("가위를 냈습니다. 그 결과 이겼습니다.\n");win++;break;}

if(rand_num==2) printf("바위를 냈습니다. 그 결과 비겼습니다.\n");

if(rand_num==3) printf("보를 냈습니다. 그 결과 졌습니다.\n");

}


if(me==3){

printf("당신은 보를 내셨습니다. 컴퓨터는 ");

if(rand_num==1) printf("가위를 냈습니다. 그 결과 졌습니다.\n");

if(rand_num==2) {printf("바위를 냈습니다. 그 결과 이겼습니다.\n");win++;break;}

if(rand_num==3) printf("보를 냈습니다. 그 결과 비겼습니다.\n");

}

continue;

}


for(win;win>0;)

{

if(win==1){

printf("현재 당신:공 컴퓨터:수\n");

printf("메뉴번호[1=가위 2=바위 3=보] : ");

scanf("%d",&me);

rand_num=rand()%(3)+1;


if(me==1){

printf("당신:찌 컴퓨터:");

if(rand_num==1) {printf("찌 로 묵찌빠를 이기셨습니다!\n");break;}

if(rand_num==2) {printf("묵 으로 공수교대\n");win=2;continue;}

if(rand_num==3) {printf("빠 로 이어서\n");continue;}

}


if(me==2){

printf("당신:묵 컴퓨터:");

if(rand_num==1) {printf("찌 로 이어서\n");continue;}

if(rand_num==2) {printf("묵 묵찌빠를 이기셨습니다!\n");break;}

if(rand_num==3) {printf("빠 로 공수교대\n");win=2;continue;}

}


if(me==3){

printf("당신:빠 컴퓨터:");

if(rand_num==1) {printf("찌 로 공수교대\n");win=2;continue;}

if(rand_num==2) {printf("묵 이어서\n");continue;}

if(rand_num==3) {printf("빠 묵찌빠를 승리하셨습니다!\n");break;}

}

}

if(win==2){

printf("현재 당신:수 컴퓨터:공\n");

printf("\n메뉴번호[1=가위 2=바위 3=보] : ");

scanf("%d",&me);

rand_num=rand()%(3)+1;


if(rand_num==1){

printf("컴퓨터:찌 당신:");

if(me==1) {printf("찌 로 묵찌빠를 패배하셨습니다!\n");break;}

if(me==2) {printf("묵 으로 공수교대\n");win=1;continue;}

if(me==3) {printf("빠 로 이어서\n");continue;}

}


if(rand_num==2){

printf("컴퓨터:묵 당신:");

if(me==1) {printf("찌 로 이어서\n");continue;}

if(me==2) {printf("묵 으로 묵찌빠를 패배하셨습니다.\n");break;}

if(me==3) {printf("빠 로 공수교대\n");win=1;continue;}

}


if(rand_num==3){

printf("컴퓨터:빠 당신:");

if(me==1) {printf("찌 로 공수교대\n");win=1;continue;}

if(me==2) {printf("묵 으로 이어서\n");continue;}

if(me==3) {printf("빠 로 묵찌빠를 패배하셨습니다.\n");break;}

}

}

}

return 0;

}


,

삼성 SDS 멀티캠퍼스 전임교수신 '천정아' 씨께서 쓰신 '개념을 콕콕 잡아주는 C 프로그래밍 초번 272쪽 예제 7-5는

visual studio 2010 및 2012에서 원래 안되는 겁니다.

복잡한 그런 프로그램도 아니고 기본서 배열 예시문에 특별한 연산도 없는 대소비교 프로그램인데 저자께서 사용하시는 visual c++ 6.0은 어떨지 모르겠으나 단순연산이 상위 버전에서 안된다는건 희안한 일입니다만, 결론은 오타로 인해 안되는게 아니라 원인을 알 수 없는 문제로 안됩니다.

 

그대로 구동하시면 값이 커졌다 작아졌다 할겁니다.

 

해당 소스의 9번째 줄에 , index 지우시고

14번째 줄 index = i; 삭제

17번째 줄 index를 i로

18번째 줄 index = j; 삭제

21,22번째 줄 index를 j로

 

바꾸셔야만 정상적으로 정렬됩니다.

 

 

 

공부하다 발견해서 저자분께 말씀 드리려 했는데 저자 연락처도 없고 출판사 회원가입을 안하면 문의를 안받네요. 전화도 안받고.

,
1
프로필 이미지
It's the Only NEET Thing to do. written by 나즈나
분류 전체보기 (256)
포트폴리오 (2)
여러가지 (160)
Windows (26)
Linux (1)
Server (5)
컴퓨터 (48)
FieldTest (1)
HTML_CSS (8)
Network (9)
PHP (4)
jQuery & Ajax (2)
C (6)
Software (1)
게임 (3)
Delphi (9)
생활수리 (0)
C# (1)
전자기기 (3)
자격증 (3)
모바일 (1)
공유기 (4)
초소형컴퓨터 (3)