현재 포인터의 위치를 잠시 기억해둘수는 없나요?

superkkt의 이미지

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

void
bin_print(unsigned int u)
{
	int max = sizeof(unsigned int) * 8 - 1;
	char *p, *p2; 
	
	p = malloc(max + 1);
	p2 = p;
	
	for(; max >= 0; max--) {
		if((u & (1u << max)) != 0) strcpy(p++, "1");
		else strcpy(p++, "0");
	}
	strcpy(p, '\0');
	
	printf("%s\n", p2);
	free(p);
}


int
main(void)
{
	bin_print(9);
	
	return 0;
}

정수값을 이진수로 보여주는 프로그램을 만들고 있습니다. strcpy에서 p++를 시키면서 포인터의 위치를 다음으로 이동시키고 있는데요.. 마지막에 널문자까지 넣고나서 이제 입력된 값들을 출력해야 되는데.. p2의 위치도 p와 동일하게 변하는것 같네요..

원래 제 의도는 초기에 메모리를 할당 받은 위치 p를 p2에 저장해 두었다가 p는 위치를 바꾸면서 데이터를 저장하고 마지막에 p2를 사용해서 저장된 데이터를 보여줄라고 했는데..

흠.. 책만 볼때는 포인터를 어느정도 배웠다고 자만했는데.. 또 좌절 중 입니다 :oops:

서지훈의 이미지

   for(int i = 0; max >= 0; max--, ++i) {
      if((u & (1u << max)) != 0) strcpy(p+i, "1");
      else strcpy(p+i, "0");
   } 

명확하게 이렇게 수정을 하시는건 어떨지 ?

근데...
이상하군요...
p2값은 변하지 않아야 정상 같은데 ㅋ
환경 정보를 좀 더 주실수 있나요 ?

<어떠한 역경에도 굴하지 않는 '하양 지훈'>

#include <com.h> <C2H5OH.h> <woman.h>
do { if (com) hacking(); if (money) drinking(); if (women) loving(); } while (1);

jhoney의 이미지

포인터형 변수에 저장되는 값은 숫자입니다.
p = p2;
라는 문장은 p 변수에 p2 값을 대입하라는 이상의 의미가 없고,
원래 포인터 값이 저장되는 게 맞습니다.

그보다는 알고리즘을 손보셔야 할 듯합니다.
변수형들에 대해서도 좀 생각해보시고요.

sangwoo의 이미지

포인터에 대해서 생각하고 계신 내용은 대부분 맞구요.
다만 사소하게 프로그램이 조금 잘못되었을 뿐입니다.
두군데만 고치면 될 것 같습니다.

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

void
bin_print(unsigned int u)
{
	int max = sizeof(unsigned int) * 8 - 1;
	char *p, *p2; 
	
	p = malloc(max + 1);
	p2 = p;
	
	for(; max >= 0; max--) {
		if((u & (1u << max)) != 0) strcpy(p++, "1");
		else strcpy(p++, "0");
	}
	strcpy(p, '\0');
	^^^^^^^^^^^

문법이 틀렸습니다. 아마 원하시는 작업은
*p = '\0'; 이었을 듯 합니다.

	printf("%s\n", p2);
	free(p);
        ^^^^^^

free(p2);
를 해주셔야겠죠? 처음에 malloc된 포인터의 주소로 free()를 해야합니다.
}


int
main(void)
{
	bin_print(9);
	
	return 0;
}

----
Let's shut up and code.

bugiii의 이미지

일단 문자열의 마지막에 널문자를 넣는 부분이 잘못되었습니다. 문자 상수가 아니라 문자열을 의도하신 듯 합니다만, 문자상수이기 때문에 잘못된 값이 들어갔을 것입니다. 아마도 경고가 발생했을텐데요.

그리고, strcpy( p++, "1" ) 같은 표현보다는 *p++ = '1'; 정도가 적당하지 않을까합니다. 굳이 복사당하는 문자열의 끝을 알 필요도 없는 상황이니까요.

상황마다 틀리겠지만 p2 는 정상적으로 최초의 포인터 값을 저장하고 있을테지만 출력할 때 널문자를 찾을 때까지 (재수없어서) '\r' 같은게 있었다면 원래 값이 안보일 수도 있습니다.

일단 strcpy( p, '\0' ) 을 "0" 로 바꾸시면 일단 동작은 할 것 같습니다.

익명 사용자의 이미지

strcpy(p++, "1");
이면 p가 증가 안할것 같은데...
p++ 해도 strcpy가 다시 원위치로 할것 같다는 느낌이 드네요. 옆에 리눅스가 없어서 테스트는 못해보고 그냥 그적

bugiii의 이미지

오... 답을 하기 위해 대기하고 있는 이 수많은 kldp 요원들~~~~ -_-; 동시에 올라오는 답글 러쉬가 대단하군요...

sangwoo의 이미지

bugiii 님 옛날에도 저랑 동시에 글을 올리셨던 적이 몇 번 있었던 듯.. :-) 좋은 글 항상 감사드립니다!

----
Let's shut up and code.

superkkt의 이미지

널문자를 추가하는 부분이 틀렸었군요.. 전 p2 = p를 대입해도 p가 변하면 p2도 따라서 변하는걸로 착각했었습니다. 빠른 답변 주신 고수님들께 감사드립니다.

그런데 문자열을 만들때 마지막에 널문자를 추가하는 방법이 조금 햇갈리는군요.. 제 생각에는 아래 두개는 별차이가 없어 보이는데 전자는 안되는군요. 단지 ', "의 차이 뿐인데..

strcpy(p, '\0');
strcpy(p, "\0");

그리고 널을 추가하려고 할때 strcpy(p, "0") 이렇게 \ 없이 0만 넣어줘도 되는건가요?

======================
BLOG : http://superkkt.com

bugiii의 이미지

죄송해요... "\0" 맞습니다...

익명 사용자의 이미지

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

void
bin_print(unsigned int u)
{
	int max = sizeof(unsigned int) * 8 - 1;
	char *p;	
	p = (char *) malloc(sizeof(unsigned int) * 8 + 1);
	
	if((u & (1u << max)))
                    strcpy(p, "1");
                else
                    strcpy(p, "0");
                max -= 1;
                while(max >= 0)
                {
                    if((u & (1u << max)))
                        strcat(p, "1");
                    else
                        strcat(p, "0");
                    p -= 1;
                }
                printf("%s\n", p2);
	free(p);

}

int
main(void)
{
	bin_print(9);
	
	return 0;
}
익명 사용자의 이미지

Anonymous wrote:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void
bin_print(unsigned int u)
{
	int max = sizeof(unsigned int) * 8 - 1;
	char *p;	
	p = (char *) malloc(sizeof(unsigned int) * 8 + 1);
	
	if((u & (1u << max)))
                    strcpy(p, "1");
                else
                    strcpy(p, "0");
                max -= 1;
                while(max >= 0)
                {
                    if((u & (1u << max)))
                        strcat(p, "1");
                    else
                        strcat(p, "0");
                    max -= 1;
                }
                printf("%s\n", p2);
	free(p);

}

int
main(void)
{
	bin_print(9);
	
	return 0;
}
sangwoo의 이미지

superkkt wrote:
널문자를 추가하는 부분이 틀렸었군요.. 전 p2 = p를 대입해도 p가 변하면 p2도 따라서 변하는걸로 착각했었습니다. 빠른 답변 주신 고수님들께 감사드립니다.

그런데 문자열을 만들때 마지막에 널문자를 추가하는 방법이 조금 햇갈리는군요.. 제 생각에는 아래 두개는 별차이가 없어 보이는데 전자는 안되는군요. 단지 ', "의 차이 뿐인데..

strcpy(p, '\0');
strcpy(p, "\0");

그리고 널을 추가하려고 할때 strcpy(p, "0") 이렇게 \ 없이 0만 넣어줘도 되는건가요?

C에서 '와 "는 전혀 다릅니다. :-) 이건 제가 설명하는 것보다 The C Programming Language 같은 책을 읽으셔서 확실히 알고 가시는 게 더 좋을 것 같습니다.
그리고 "0", '0', '\0' 은 전혀 다른 녀석들입니다. 제일 앞의 녀석은 0다음에 nul이 붙어 있는 곳을 가리키는 포인터이고, 두번째 녀석은 ASCII 코드로 0x30, 세번째 녀석은 ASCII코드 0x00, 즉 nul character입니다.

----
Let's shut up and code.

cinsk의 이미지

무슨 이유에서인지는 모르겠지만, 한 문자씩 복사할 때 strcpy()를 쓰는 것은 보기 좋지 않습니다. '\0'를 겹쳐 쓰는 것이 반복되기 때문이며, 함수 호출에 의한 오버헤드도 큽니다. (예: *p++ = '1')

char가 8bit라고 가정하지 말고, <limits.h>를 포함시켜 CHAR_BIT을 쓰기 바랍니다.

또 malloc()으로 할당한 메모리를 free()할 때, 잘못된 pointer 값을 주었기 때문에, 제대로 동작하지 않습니다.

마지막으로, max값을 <<에서 쓰기 위해 loop가 31에서 0과 같거나 클때까지 반복되는데, 이런 식으로 하면 읽기 어렵습니다. 차라리 loop를 32에서 0보다 클 때까지 돌리고 "<< (max - 1)"과 같이 쓰는 것이 읽기 편합니다.

bugiii의 이미지

일은 많지만 (게으르고... 일하기 싫어서) 심심해서 손님께서 만드신 코드의 문제점을 한번 살펴보았습니다. 문제점이라기보다는 저라면 이렇게 할 것 같다는 것이니 오해는 마시고요.

일단 p2 변수가 선언되지 않았으므로 컴파일 에러가 날 것 같습니다.
각 비트가 1인지 0인지 판단하는 부분이 중복되는 이유가 분명하지 않습니다. 만약 그 이유가 strcpy 와 strcat 의 차이라고 해서 코딩했다면 지금 같은 경우는 동일한 동작이므로 차이가 없습니다.
문자를 하나 복사하는데, 문자열 복사하는 함수를 호출하는 것은 낭비입니다.
1을 감소시키는 표현은 --max 로 충분할 것 같습니다.
max 라는 이름이 (매크로 등으로) 문제가 될 소지가 있습니다.
비교당하는 값을 변수로 만들어서 최상위 비트를 세팅한 후에 오른쪽으로 쉬프트하는게 어떨까요?
free(p) -> free(p2) 해야겠지요.
마지막으로 동적 할당이 과연 필요할까요?

superkkt의 이미지

고수님들의 조언대로 좀 고쳐봤습니다. 이젠 잘 된건지 모르겠네요 :oops:

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

void
bin_print(unsigned int u)
{
	int i, max = sizeof(unsigned int) * 8;
	char *p;
	
	p = malloc(max);
	
	for(i = 0; max > 0; max--, i++) {
		if((u & (1u << (max - 1))) != 0) p[i] = '1';
		else p[i] = '0';
	}
	p[i] = '\0';
	
	printf("%s\n", strstr(p, "1"));
	
	free(p);
}


int
main(void)
{
	bin_print(10);
	
	return 0;
}

cinsk wrote:
char가 8bit라고 가정하지 말고, <limits.h>를 포함시켜 CHAR_BIT을 쓰기 바랍니다.

그런데 이 부분은 잘 이해가 안됩니다. 제가 만든 코드 중 어느 부분이 char를 8bit로 가정한것인지... :?:

======================
BLOG : http://superkkt.com

superkkt의 이미지

superkkt wrote:
int i, max = sizeof(unsigned int) * 8;

음.. 이 부분을 말씀하신건가보네요.. 1바이트가 8비트라고 가정하지 말라는 뜻인거죠?

======================
BLOG : http://superkkt.com

bugiii의 이미지

char 형의 비트수가 8 이라는 가정이 사실이 아닌 플랫폼도 있다는 것을 지적하신 것 같습니다.

doldori의 이미지

superkkt wrote:
고수님들의 조언대로 좀 고쳐봤습니다. 이젠 잘 된건지 모르겠네요 :oops:

이렇게 하셔야죠.
	p = malloc(max + 1);

그런데 제가 보기에 굳이 malloc()을 쓸 이유가 없군요. 그냥 배열을 쓰는 편이 쉽습니다.

void 
bin_print(unsigned int u) 
{ 
    int max = sizeof(unsigned int) * CHAR_BIT; 
    char p[max + 1];
    /* ... */
} 
doldori의 이미지

bugiii wrote:
죄송해요... "\0" 맞습니다...

실은 ""를 의도하신 거겠죠? :wink:
singlet의 이미지

여기 있던 글, 제 실수였기에 삭제했습니다. (실험삼아 돌려보다 다른 데서 에러 난 걸 착각했습니다. :oops:) 읽으신 분들께 죄송합니다.

superkkt의 이미지

doldori wrote:
그런데 제가 보기에 굳이 malloc()을 쓸 이유가 없군요. 그냥 배열을 쓰는 편이 쉽습니다.
void 
bin_print(unsigned int u) 
{ 
    int max = sizeof(unsigned int) * CHAR_BIT; 
    char p[max + 1];
    /* ... */
} 

제가 지금 "C 언어 펀더멘탈"이라는 책으로 공부를 하고 있는데요.. 이 책에 보면 가변적인 배열은 c99 이전 표준에서는 정의되지 않았다고 나오네요. gcc가 에러없이 컴파일해줘도 어디까지나 컴파일러가 제공하는 확장 기능일 뿐이라고 하는데.. 뭐.. 아직까지 제가 만드는 코드들은 별 상관이 없겠지만 그냥 갑자기 궁금해져서요..

완벽한 이식성을 가지는 프로그램을 만들려면 가변적인 배열을 사용하지 말아야 하는건가요?

======================
BLOG : http://superkkt.com

doldori의 이미지

C90과의 호환성을 생각한다면 가변 배열을 쓰면 안되겠죠. 하지만 호환성을
유지하면서 배열을 쓸 수도 있습니다. 배열의 크기는 컴파일 타임 상수여야
한다는 조건을 이용한 것입니다. 이는 이 코드에서 malloc()을 쓰지 않아도 되는
이유와도 같은 것입니다.
char p[sizeof(unsigned int) * CHAR_BIT + 1];

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.