C언어. 포인터, 할당, gets()

cpu101의 이미지

안녕하세요.
C언어를 공부하고 있습니다.
배열과 포인터연습을 하려고 해당 문자열을 입력받으면 그 역순으로 출력하는 프로그램을 짜봤는데요(도스의 strrev()함수처럼)....
도스상에서(터보씨 2.0) 컴파일하면 내부적으론 어떨런지 모르지만 이상없이 출력이 됩니다.

그런데 리눅스(gcc 2.96)에서 컴파일하면 컴파일이 안되고 이런메세지가 뜹니다.
the 'gets' function is dangerous and should not be used.
유닉스계열에서도 gets() 함수지원되는거 아닌가요? 그렇게 알고있었는데..
암튼 임시방편으로 scanf()함수를 써서 컴파일 하니까 컴파일되고 a.out파일을 실행하니까 일곱문자까지만 정확하게 바꿔지고 8문자이상이면 결과는 나오는데 마지막에 "중지됨(core dumped)" 메세지가 같이 나옵니다.

소스가 길지 않으니까 한번 봐주세요.

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

char *s_convert(char *p);                  /* 함수선언 strrev() 함수와 원형이 같습니다 */

int main() {
   char *sp;
   printf("Input String : ");
   gets(sp);                            /* 리눅스에서 안돼서 나중에 scanf("%s",sp); 로 바꿈*/
   printf("Convert String : %s\n",s_convert(sp));
   return 0;
   }

char *s_convert(char *p) {               /* 함수구현 */
   int i,len;
   char *cp;
   cp=(char *)malloc(100);
   
   if (cp==NULL) {
      printf("allocation failed");
      exit(1);
      }

   len=strlen(p);
   for (i=len-1; i>=0; i--) cp[i]=p[len-1-i];
   cp[len]='\0';
   return cp;
   }
wind772의 이미지

gets() 함수를 쓰면 버퍼오버플로우의 위험이 있어서 경고 메세지가 뜹니다.
그리고 위에 쓴 소스가 에러가 나는 이유는 포인터를 초기화 하지 않은 상태에서 문자열을 입력했네요..^^


int main() { 
   char *sp; 
   printf("Input String : "); 

   gets(sp);  <- 이부분.. 초기화되지 않은 포인터 사용 !!

   printf("Convert String : %s\n",s_convert(sp)); 
   return 0; 
   } 

배열을 잡던가 동적 메모리 할당을 해서 문자열을 입력하면 제대로 출력될겁니다.

===================================================
중요한건 얼마나 아느냐가 아니라 그것에 대한 열정이다.

mini7662의 이미지

fgets() 써보세요....

원형 : char * fgets( char *s, int size, FILE *stream )

*s 는 저장할 버퍼, size는 버퍼의 크기, *stream 은 stdin 으로 하시면 될꺼구요...

malloc 하구 free 안 하는건 좀...ㅡㅡ;

s_convert 에서 malloc 하구 포인터 넘겨주는 것 보단

main 에서 버퍼잡고 s_convert 에 포인터 넘겨줘서

처리 하는게 나을 듯 하군요...

dyaus의 이미지

char   *s_convert(char *p)
{
        int     i,len;

        char    *cp;

        len=strlen(p);
        cp = (char *)malloc(sizeof(char)*len);
        if (cp == NULL) {
                perror("allocation failed");
                exit(1);
        }

        for (i=0;i<len; i++) {
                *(cp+i) = *(p+len-1-i);
        }

        *(cp+len) = 0x00;

        memcpy(p, cp, len);

        free(cp);

        return p;
}

엉성하지만 조금 바꿔봤습니다.
생각나는데로 코딩한거라서 --:

익명 사용자의 이미지

C++로 예전에 맹글었던겁니다. reverse함수는 일반적인 루틴을 따른겁니다.
han_reverse는 심심해서리...-.-;;

#include <iostream>
using namespace std;

char* reverse(char* s)
{
		if(s == 0) return 0;
		int len = strlen(s);
		int count = len / 2;
		char c;

		for(int i = 0; i < count; i++){
				c = s[i];
				s[i] = s[len - 1 - i];
				s[len - 1 - i] = c;
		}
		return s;
}

char* han_reverse(char* s)
{
		if(s == 0) return 0;
		int len = strlen(s);
		char fc, sc; // first char, second char
		int i, j;

		for(i = 0, j = len - 1; i < j; i++, j--){
				if(s[i] < 0){ // if hangul
						if(s[j] < 0){ // if hangul
								fc = s[j - 1];
								sc = s[j];
								s[j - 1] = s[i];
								s[j] = s[i + 1];
								s[i] = fc;
								s[i + 1] = sc;
								i++; // because hangul 
						}else{
								fc = s[i];
								sc = s[i + 1];
								s[i] = s[j];
								for(int n = i + 1; n < j - 1; n++){
										s[n] = s[n + 1];
								}
								s[j - 1] = fc;
								s[j] = sc;
						}
						j--; // because hangul
				}else{
						if(s[j] < 0){ // if hangul
								fc = s[j - 1];
								sc = s[j];
								s[j] = s[i];
								for(int n = j - 1; n > i + 1; n--){
										s[n] = s[n - 1];
								}
								s[i + 1] = sc;
								s[i] = fc;
								i++; // because hangul
						}else{
								fc = s[i];
								s[i] = s[j];
								s[j] = fc;
						}
				}
		}
		return s;
}


int main(int argc, char *argv[])
{
		char buffer[BUFSIZ];
		int h_mode = 0; // hangul mode off

		if(argc == 2){
				if(strcmp(argv[1], "-H") == 0){
						h_mode = 1; // hangul mode on
				}
		}

		do{
				cout << "INPUT>";
				cin.getline(buffer, BUFSIZ);
				if(strncmp(buffer, "exit", 4) == 0) break;
				if(h_mode) han_reverse(buffer);
				else reverse(buffer);
				cout << buffer << endl;
		}while(1);
		return 0;
}
cdpark의 이미지

debugging.. :)

dyaus 님의 코드:
(1) strlen+1 길이만큼 메모리를 잡아야 합니다.
(2) 그리고 sizeof(char)는 언제나 1이므로 생략해도 무방합니다.

no4822님의 코드:
한글에 대해서도 동작하고, inplace reverse이긴 합니다만...
(1) if (s[i] < 0) : signed char인 환경에서만 동작합니다. unsigned char인 환경에서는 이식성이 떨어집니다.
(2) if (s[j]< 0) : 한글의 뒷 바이트만 가지고 이게 한글의 한 글자인지 판단하는 것은 "완성형"에서만입니다. 조합형이나 MS의 "확장완성형"에서는 이런 식으로 판단할 수 없습니다. "햏"같은 글자에서 문제를 일으킬 수 있습니다.
(3) 한글과 영문이 혼합된 문장을 뒤집으려면 최악의 경우 O(n^2) 시간이 걸립니다. 그냥 간단히 새로 buffer를 잡아서 옮긴다면 O(n) 시간에 끝낼 수도 있습니다.

이 단점을 보완해서 no4822님의 코드를 고치면... (확인과 테스트를 거치지 않았습니다. 버그가 있을 수 있습니다. 버그가 없다 하더라도 실제 사용하려면 주석에 적은 부분을 좀 더 보완해야 합니다. )

#define IS_HAN(c)       ((c)&0x80)
char * str_rev (char *dest, const char *src)
        /* dest에는 충분히 src를 복사할 공간이 있다 */
        /* src는 제대로 된 한글/영문 혼용문이다. 즉 second byte가 없는
         *  글자는 없다. */
{
    int len=0;
    int count=0;
    int i;
    char *p, *q;

    if (src == 0)
        return 0;

    len = strlen(src);

    for (p = src, q = dest + len - 1; *p != 0; )
    {
        if (IS_HAN(*p))
              /* 다시 적지만 *(p+1) 이 '\0'인 경우 동작하지 않을 수 있습니다. */
        {
            q -= 2;
            q[0] = p[0];
            q[1] = p[1];
            p += 2;
        }
        else
        {
            -- q;
            q[0] = p[0];
            ++ p;
        }
    }
    dest[len] = 0;

    return dest;
}


char *han_reverse(char *s)
{
    static char *buf = NULL;
    static int buf_len = 0;
    int len;

    if (s == 0)
        return 0;

    len = strlen(s);

    if (buf_len <= len)
    {
        free(buf); /* free(NULL)이 동작하지 않을 수 있다. 주의! */
        buf_len = len * 2 + 4; /* 이 공식은 입맛에 따라 요리 */
        buf = malloc(buf_len + 1); /* malloc 실패에 대한 확인을 해야 합니다. */
    }

    str_rev(buf, s);

    return strcpy(s, buf);
}

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.