질문: [C언어]이 프로그램 내에서 이중 포인터를 사용하는 이유가 뭔가요? nucleus824 / 2005-01-21 22:39
링크드리스트를 작성한 프로그램입니다..

여기서 이해 안되는곳이 insertNode라는 함수에서 첫번째 인자값을

이중 포인터로 선언되어있는데 왜 그런가요??

#include
#include

struct listNode {

char data;
struct listNode *nextPtr;

};

typedef struct listNode ListNode;
typedef ListNode *ListNodePtr;

ListNodePtr createNode(void);
void destroyNode(ListNodePtr);
int insertNode(ListNodePtr *, ListNodePtr);
char deleteNode(ListNodePtr *, char);
int isEmpty(ListNodePtr);
void printList(ListNodePtr);
void instructions(void);

int main()
{
ListNodePtr startPtr = NULL;
ListNodePtr creNodePtr = NULL;
int choice;
char item;

instructions();
printf("?");
scanf("%d", &choice);

while(choice != 3) {
switch(choice) {

case 1:
if( (creNodePtr = createNode() ) == NULL ) break;
if( insertNode( &startPtr, creNodePtr) == -1) {
destroyNode( creNodePtr );
break;
}

printList( startPtr );
break;

case 2:
if( !isEmpty( startPtr ) ) {
printf( "Enter character to be deleted: ");
scanf( "\n%c", &item );
if ( deleteNode( &startPtr, item ) ) {
printf("%c deleted.\n", item );
printList( startPtr );
}
else
printf( "%c not found.\n\n", item );
}
else
printf( "List is empty.\n\n" );
break;
default:
printf( "Invalid choice.\n\n" );
instructions();
break;
}

printf( "? " );
scanf( "%d", &choice );
}

printf( "End of run.\n" );
return 0;
}


ListNodePtr createNode(void) {
ListNodePtr newPtr;

newPtr = (ListNodePtr)malloc( sizeof( ListNode ) );

if( newPtr != NULL ) {
newPtr->nextPtr = NULL;
printf( "Enter a character: " );
scanf( "\n%c", &newPtr->data );
return newPtr;
} else {
printf( "Node is not created. No memory available.\n" );
return NULL;
}
}

void destroyNode( ListNodePtr desPtr ) {
free( desPtr );
}

void instructions( void ) {
printf( "Enter your choice:\n"
" 1 to insert an element into the list.\n"
" 2 to delete an element from the list.\n"
" 3 to end.\n");
}

int insertNode( ListNodePtr *sPtr, ListNodePtr newPtr ) {
ListNodePtr previousPtr, currentPtr;
char keyValue;

previousPtr = NULL;
currentPtr = *sPtr;

keyValue = newPtr->data;

while ( currentPtr!=NULL && keyValue > currentPtr->data ) {
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}

if( currentPtr != NULL && currentPtr->data == keyValue ) {
printf("\n%c is alread existed...\n", keyValue );
return -1;
}

if( previousPtr == NULL ) {
newPtr->nextPtr = *sPtr;
*sPtr = newPtr;
}
else {
previousPtr->nextPtr = newPtr;
newPtr->nextPtr = currentPtr;
}

return 0;
}

char deleteNode( ListNodePtr *sPtr, char keyValue ) {
ListNodePtr previousPtr, currentPtr, tempPtr;

if( keyValue == (*sPtr)->data ) {
tempPtr = *sPtr;
*sPtr = ( *sPtr )->nextPtr;
destroyNode( tempPtr);
return keyValue;
}
else {
previousPtr = *sPtr;
currentPtr = ( *sPtr )->nextPtr;

while( currentPtr != NULL && currentPtr->data != keyValue )
{
previousPtr = currentPtr;
currentPtr = currentPtr->nextPtr;
}

if( currentPtr != NULL ) {
tempPtr = currentPtr;
previousPtr->nextPtr = currentPtr->nextPtr;
destroyNode( tempPtr );
return keyValue;
}
}

return '\0';
}

int isEmpty( ListNodePtr sPtr)
{
return sPtr == NULL;
}

void printList( ListNodePtr currentPtr )
{
if( currentPtr == NULL )
printf( "List is empty.\n\n" );
else {
printf( "The list is:\n" );

while( currentPtr != NULL ) {
printf( "%c -> ", currentPtr->data );
currentPtr = currentPtr->nextPtr;
}

printf( "NULL\n\n" );
}
}
답변: re: [C언어]이 프로그램 내에서 이중 포인터를 사용하는 이유가 뭔가요? iindra81 / 2005-01-21 01:23
포인터는 이해하기가 어렵죠 ㅠ ㅅ ㅠ 제대로 개념을 잡지 못하면 상당히 헤메게 됩니다..;; (나는 과연 제대로 알고있을까..ㅋ) 아무튼 문제에 대한 답변을 하자면요.. 위의 프로그램에서 ListNode x 라고 ...

Posted by 김용환 '김용환'

댓글을 달아 주세요

assert의 응용

c or linux 2005. 3. 9. 01:49

assert((ch=getchar())!=EOF);

는 잘못되었다. assert 구문은 디버그용이라서 실제 배포용 버젼에서는 assert구문이 생략된다. 그렇다면! ch=getchar()는 문제가 된다! 이를 빼고 assert(ch!=EOF)라고 하자

 

switch case 문에서 case목록에 포함이 되지 않을 경우 default에 assert(FALSE)를 추가한다!!!!

 

 

 

메모리 블럭을 항달한 뒤에 초기화하지 않고, 저장되어 있던 내용을 사용한다.

 

메모리 블럭의 소유권을 해제(free)한 뒤에도, 그 내용을 계속 사용(reference)한다.

 

블럭을 확장하기 위해 realloc을 호출하여 블럭의 내용이 이동중인데도, 이전 위치의 내용을 계속 사용한다.

 

블럭은 할당되었으나, 그 포인터를 저장하지 않아서 블럭을 읽어버린다.

 

블럭의 경계를 넘어, 읽고 쓰기를 한다.

 

에러 상황을 경고하지 못한다.

 

 

Posted by 김용환 '김용환'

댓글을 달아 주세요

함수의 인수를 확인하기 위해 assertion을 사용한다! | Writing Solid Code 2004/12/30 16:28
http://blog.naver.com/bravedog/100008948045
  1  /* memcpy -- 겹치지 않는 메모리 블록을 복사한다. */
  2
  3  void *memcpy(void *pvTo, void *pvFrom, size_t size)
  4  {
  5      void *pbto = (void *)pvTo;
  6      void *pbFrom = (void *)pvFrom;
  7
  8      if(pvTo == NULL || pvFrom == NULL){
  9          fprintf(stderr, "bad args in memcpy\n");
 10          abort();
 11      }
 12      while(size-- > 0)
 13          *pbTo++ = *pbFrom++;
 14      return (pvTo);
 15  }
 16
 17
 18  /*
 19   * 위의 프로그램은 void * 변수들이 NULL을 가리키고 있을시의 exception 처리를 
 20   * 보여주고 있다. 헌데, 저 줄은... 낭비가 아니라고 할수가 없다.... 
 21   * 낭비이다!!!!! debug할때는 필요하지만 배포용으로 컴파일 할때는 필요가 없다
 22   * 그래서!!!!
 23   * 다음과 같이 #ifdef , #endif 를 이용하여 DEBUG가 정의되었을 때만 실행하도록
 24   * 변경하자~~~~~~~~~~
 25   */
 26
 27  void *memcpy(void *pvTo, void *pvFrom, size_t size)
 28  {
 29      void *pbto = (void *)pvTo;
 30      void *pbFrom = (void *)pvFrom;
 31
 32  #ifdef DEBUG
 33      if(pvTo == NULL || pvFrom == NULL){
 34          fprintf(stderr, "bad args in memcpy\n");
 35          abort();
 36      }
 37  #endif
 38      while(size-- > 0)
 39          *pbTo++ = *pbFrom++;
 40      return (pvTo);
 41  }
 42
 43  /* 자~ 이젠 Debug할때만 (DEBUG가 정의되어 있을때만) 저 안의 구문이 실행되도록
 44   * 바꾸어 보았다! 쉽다...  ㅋㅋㅋㅋ
 45   * 헌데~ 오늘 말하고 싶은 내용은 이 7줄의 #ifdef 와 #endif 안의 내용을 한줄로
 46   * 처리할 수 있다. assert()는 ANSI assert.h 헤더 파일에 정의되어 있는 assert라는
 47   * 이름의 매크로에 숨겨 두기 때문이다.
 48   * assert는 우리가 앞에서 보았던 #ifdef 코드를 재구성한 형태에 불과하다~~~~!!!!
 49   * 한줄로 바꾸어 볼까?
 50   */
 51
 52  void *memcpy(void *pvTo, void *pvFrom, size_t size)
 53  {
 54      void *pbto = (void *)pvTo;
 55      void *pbFrom = (void *)pvFrom;
 56
 57      assert(pvTo != NULL && pvFrom != NULL);
 58
 59      while(size-- > 0)
 60          *pbTo++ = *pbFrom++;
 61      return (pvTo);
 62  }
 63
 64
 65
 66  /*--------------------------------------------------------------------------------
 67   * assert 이용시 주의사항
 68   *
 69   * assert는 단지 집어넣기만 하면 되는 매크로는 아니다. 이것은 조심스럽게 정의해서
 70   * 프로그램의 판매용과 디버그 버전 사이에 중대한 차이를 야기하지 않도록 해야 한다.
 71   * assert는 메모리를 혼란시키지 말아야 하고 그냥두면 초기화되지 않는 데이터를 
 72   * 초기화해야 한다. 그렇지 않으면 어떤 부작용을 일으킬 수도 있다. 
 73   * 이것이 assert가 함수가 아니고 매크로인 이유이다.
 74   * assert가 함수라면, 이것을 호출하면 예기치 않은 메모리나 코드스워핑(swapping)을 
 75   * 발생시킬 수 있다. assert를 사용하는 프로그래머는, 이것을 시스템이 어떤 상태에 
 76   * 있든 안전하게 사용할 수 있는 무해한 검사로 본다는 점을 기억해야 한다.
 77   * ------------------------------------------------------------------------------*/
 78
 79
 80
 81  /* assert를 직접 정의하여 자신만의 assert를 만들어 DEBUG용으로 쓸수있다*/
 82  #ifdef DEBUG
 83      void my_assert(char *, unsigned);       /* 원형 */
 84      #define ASSERT(f)       \
 85          if (f)              \
 86              NULL;           \
 87          else
 88              my_assert(_FILE_,_LINE_)
 89  #else
 90      #define ASSERT(f) NULL
 91  #endif
 92  /* ASSERT가 실패했을 때, 이것은 선행처리기에 의해, _FILE_과 _LINE_ 매크로를 통해 
 93   * 제공되는 파일 이름과 행번호를 갖고 my_assert를 호출한다.
 94   * my_assert는  stderr에 에러 메시지를 표싷고 수행을 중단시킨다.
 95   */
 96
 97  void my_assert(char *strFile, unsigned uLine)
 98  {
 99      fflush(stdout);
100      fpinrtf(stderr, "\nAssertion failed : %s, line %u\n",
101              stdFile, uLine);
102      fflush(stderr);
103      abort();
104  }
105

 

 

⊙ 요약 ⊙

◇ 프로그램을 판매용과 디버깅용의 두 가지 버전으로 관리한다. 판매용 버전은 군더더기 코드를

    빼고 날씬하게 유지한다. 그러나 버그를 빨리 발견하기 위해 가능한 한 디버깅 버전을 사용한다.

◇ assertion은 디버깅 검사 코드를 작성하는 속성의 방법이다. 결코 발생하지 않을 규정에 어긋나

    는 조건(illegal condition)을 발견하기 위해 이를 사용한다. 이들 조건(illegal condition)과 에

    러 조건(error condition)을 혼동하지 않도록 주의한다. 익서은 최종적인 프로그램에서 처리해

    야 한다.

◇ 함수의 인자(argument)의 유효성을 검사하고, 프로그래머들이 정의되지 않은(undefined) 어

    떤 작업을 하면 경고하기 위해 assertion을 사용한다. 여러분의 함수들을 보다 엄격하게 정의할

    수록, 인자의 유효성을 검사하는 것이 보다 쉬워진다.

◇ 일단 함수를 작성하면, 그것을 재검토하고 스스로에게 "나는 무엇을 가정하는가?"라고 묻는다.

    가정한 것이 있다는 것을 발견하면, 여러분의 가정이 항상 유효한지 assert하거나, 또는 가정을

    제거하기 위해 코드를 재작성한다. 또한 "이 코드에서 가장 잘못될 만한 것은 무엇인가? 그리고

    그 문제를 어떻게 하면 자동으로 발견할 수 있는가?"를 묻는다. 가능한 한 가장 빠른 시간에 버

    그를 발견하는 검사를 구현하도록 노력한다.

◇ 교과서는 프로그래머에게 방어적으로 프로그램을 작성하도록 권고한다. 그러나 이러한 코딩 방

    식은 버그를 감춘다는 점을 기억해야 한다. 벙어적인 코드를 작성할 때는, "발생할 수 없는" 경

    우가 발생할 경우, 경고해 줄 수 있는 assertion을 사용한다.

Posted by 김용환 '김용환'

댓글을 달아 주세요

불행히도, 원형은 같은 유혀의 두 개의 인수를 교환할 때는 호출 버그를 알려주지 않는다. 예를 들어, memchr 함수가 다음과 같은 원형을 갖는다면,

 

void * memchr(const void *pv, int ch, int size);

 

문자(char)와 크기(size) 인수를 교환할 수 있고 컴파일러는 경고를 내지 않을 것이다. 그러나 인터페이스와 원형에 보다 정확한 유형(type)을 사용함으로써, 원형이 제공하는 에러 검사 기능을 강화할 수 있다. 예를 들어, 아래와 같은 원형은 문자와 크기 인수를 바꿔 기입한다면, 버그에 대한 경고를 내보낼 것이다.

 

void * emmchr(const void *pv, unsigned char ch, size_t size);

 

보다 정확한 유형을 사용하는데 있어서의 단점은, 유형 불일치(type-mismatch) 경고가 나오지 않게 하기 위해 인수를 정확한 유형으로 자주 배정해야 한다는 것이다.

'c or linux' 카테고리의 다른 글

assert의 응용  (0) 2005.03.09
함수의 인수를 확인하기 위해 assertion을 사용한다  (0) 2005.03.09
원형(prototype) 강화하기  (0) 2005.03.09
배열 포인터  (0) 2005.03.09
void 형 포인터와 널 포인터  (0) 2005.03.09
포인터의 포인터  (0) 2005.03.09
Posted by 김용환 '김용환'

댓글을 달아 주세요

배열 포인터

c or linux 2005. 3. 9. 01:34

배열 포인터란 배열의 주소를 가리키는 포인터. 배열 포인터는 함수의 인자가 메모리가 큰 배열일 경우 유용하게 사용될 수 있다. 배열 포인터는 다음과 같이 선언된다.

데이터 형 (*포인터명)[크기];

 

예를 들어서

int (*array_pointer)[2];

위의 예제가 의미하는 것은 크기가 2인 배열을 가리키는 포인터이다. 포인터의 연산에서 증가 연산을 하면 int형의 2배 크기(4byte)만큼 주소 값이 증가한다.

 

예제

 1  #include <stdio.h>
 2
 3  int main()
 4  {
 5      int i, j;
 6      int array[3][2] = {5,10,6,12,7,14};
 7      int (*pointer_array)[2];
 8
 9      for(j=0;j<3;j++)
10          for(i=0;i<2;i++)
11              printf("array[%d][%d]=%d\n",j,i,array[j][i]);
12
13      pointer_array=array;
14
15      for(j=0;j<3;j++){
16          for(i=0;i<2;i++)
17              printf("pointer_array[%d]=%d\n",i,(*pointer_array)[i]+1);
18          pointer_array++;
19      }
20
21      return 0;
22  }
23

결과

 


 
배열 포인터를 사용하는 방법은 여러 가지이지만 위의 예에서는 배열의 주소를 배열 포인터에 대입하였다. 배열은 3X2의 2차원 행렬이나 배열 포인터는 크기 2의 1차원 배열 형태이다. 포인터 연산자를 이용하여 배열 포인터를 증가함으로써 3*2의 각 요소를 접근할 수 있도록 되어있음을 알 수 있다.

'c or linux' 카테고리의 다른 글

함수의 인수를 확인하기 위해 assertion을 사용한다  (0) 2005.03.09
원형(prototype) 강화하기  (0) 2005.03.09
배열 포인터  (0) 2005.03.09
void 형 포인터와 널 포인터  (0) 2005.03.09
포인터의 포인터  (0) 2005.03.09
동적 메모리 - 메모리 할당  (0) 2005.03.09
Posted by 김용환 '김용환'

댓글을 달아 주세요

void 형 포인터와 널 포인터 | c Note 2004/09/06 21:49
http://blog.naver.com/bravedog/100005562577

void 포인터란 데이터 형이 정해지지 않은 포인터를 말한다. 프로그램을 만드는 경우 필요에 따라서  여러 타입의 데이터형을 일괄적으로 처리할 일이 발생한다. 하지만 각각의 데이터 형마다 포인터를 만든다면 메모리의 낭비도 발생할 뿐만 아니라 소스가 엄청나게 길어진다. 이러한 문제를 해결하기 위한 포인터가 바로 void 포인터이다. void 포인터는 개게가 존재하는 위치와 타입만 알면 하나의 포인터로 여러 데이터 형을 처리할 수 있다.

 

void 포인터는 타입캐스팅이 없이는 참조할 수가 없다. 그 이유는 포인터가 가리키는 객체의 크기를 컴파일러가 결정할 수 없기 때문이다. 또한 void 포인터는 포인터 연산을 할수가 없다. 일반적으로 void 포인터는 메모리에 직접 접근할 대 사용한다.

 

다음 예제를 보고 void 포인터의 사용법을 알아보자.

 1  #include <stdio.h>
 2
 3  int main()
 4  {
 5      int x = 3;
 6      float f = 0.0f;
 7      void *p;            // void 형 포인터 선언
 8
 9      // 기존 값 출력
10      printf("x = %d, f = %f\n",x,f);
11
12      p = &x;             // x를 가리킨다
13      *(int*)p = 2;
14      p = &f;             // f를 가리킨다
15      *(float*)p=1.5f;
16
17      // 변경 값 출력
18      printf("x = %d, f = %f\n",x,f);
19
20      return 0;
21  }

 

결과화면

 

 

 

 

 

 

 

 

 

위의 예제에서 void 형 포인터 변수 p를 이용하여 각각의 변수에 값을 대입할 경우 타입캐스팅이 일어났음을 확인할 수 있다. 주의할 점은 void 형 포인터 변수 p도 포인터이기 때문에 타입캐스팅을 할 경우 데이터 형 뒤에 반드시 '*'을 붙이기 바란다.

 

 

한편, 포인터 중에는 아무 것도 가리키지 않는 NULL 포인터라는 것이 있다. NULL 포인터는 포인터의 초기화나 비교, 리턴값으로 많이 사용한다. 그럼 NULL포인터의 쓰임새를 잠시 살펴보자.

 

첫 번째로 NULL 포인터는 포인터의  초기화를 위해서 많이 사용된다. 예를 들어 나중에 사용할 포인터이지만 현재는 아무 것도 가리키지 않고 있다는 의미를 주기 위해서 NULL포인터로 초기화한다

 

int *pLater = NULL;

 

두 번재로 NULL 포인터는 현재 포인터가 가리키는 곳이 있는지 없는지를 확인하기 위해서 비교의 용도로 많이 사용된다. 따라서 어딘가 가리키는 곳이 있다면 그 포인터는 NULL이 될 수가 없겠지!?

 

if(pLater == NULL){

    // 가리키는 곳이 없으므로 포인터 사용불가

}

else {

    // 가리키는 곳이 있으므로 포인터 사용가능

}

 

이러한 비교식에서 C언어는 편리성을 위해 다음과 같이 간단한 표현식을 사용할 수 있다.

if(!pLater){}

위의 표현은 부정 연산자(!)를 사용한 것인데 '포인터 형 변수 pLater가 가리키는 곳이 없으면'라는 의미를 가진다. 'NULL 포인터와 같다'는 의미와 상통한다.

 

세 번째로 NULL 포인터는 메모리가 할당되지 않았음을 의미한다. 예를 들어 동적 메모리를 생성하는 malloc함수는 메모리 생성에 실패하면 NULL포인터를 리턴한다. 만약 NULL포인터를 리턴한다면 메모리가 생성되지 않았으므로 사용하면 안되겠지?

 

// 메모리 할당

pLater = (int*)malloc(10*sizeof(int));

if(pLater == NULL){

    // 메모리가 생성되지 않았으므로 처리

}

 

이렇게 NULL 포인터가 사용되는 용도는 크게 세 가지 정도로 정리할 수 있다.

 

그럼 좀 더 나아가 NULL포인터의 내부로 들어가 보자.

 

#define NULL 0

 

NULL 포인터가 0으로 정의되어 있지만 반드시 0이지는 않다. 환경에 따라서 NULL 포인터는 다른 값을 수도 있다. 그렇지만 공통적으로  NULL이란 매크로를 사용한다는 것을 기억해 두기 바란다. 개인적으로는 NULL이란 매크로를 사용할 것을 추천한다.

 

 

tip

포인터를 이용하여 프로그램을 하다보면 실행중에 다음과 같은 문장을 종종 발견할 수 있다.

null pointer assignment

이 메시지는 초기화하지 않은 포인터를 사용하여 잘못된 위치에 데이터를 쓰려고 할 때 발생한다. 이러한 경우는 초기화하지 않고 사용하는 포인터가 있는지 확인해 보기 바란다.

'c or linux' 카테고리의 다른 글

원형(prototype) 강화하기  (0) 2005.03.09
배열 포인터  (0) 2005.03.09
void 형 포인터와 널 포인터  (0) 2005.03.09
포인터의 포인터  (0) 2005.03.09
동적 메모리 - 메모리 할당  (0) 2005.03.09
동적 메모리 - 메모리 크기 변경  (0) 2005.03.09
Posted by 김용환 '김용환'

댓글을 달아 주세요

포인터의 포인터 | c Note 2004/09/06 21:27
http://blog.naver.com/bravedog/100005561904

포인터의 포인터는 보통 이중 포인터라고 부른다. 이중 포인터는 현재 가리키는 주소가 변수의 주소가 아니라 다른 변수를 가리키는 포인터의 주소를 가리킨다. 이중 포인터를 주로 사용하는 경우는 2차원 구조를 가지는 메모리의 주소를 가리킬 대이다.

 

데이터 형 **포인터변수명;

 

이중 포인터를 사용하여 가리키는 주소의 값을 알고 싶은 경우에는 포인터 형 변수 앞에 '*'를, 가리키는 주소의 포인터가 다시 가리키는 주소의 값을 알고 싶은 경우에는 '**'를 사용한다. 이해를 돕기 위해서 프로그램을 통해 설명해 보도록 하겠다.

 

 1  #include <stdio.h>
 2
 3  int main()
 4  {
 5      int num =24;
 6      int *p;
 7      int **pp;
 8
 9      // 포인터 설정
10      p = &num;
11      pp =&p;
12
13      // 1차원 포인터
14      printf("*p = %d\n",*p);
15      printf("p = %p\n",p);
16      printf("&p = %p\n",&p);
17
18      // 2차원 포인터
19      printf("pp = %p\n",pp);
20      printf("*pp = %p\n",*pp);
21      printf("**pp = %d\n",**pp);
22
23      return 0;
24  }
25

 

결과 화면

 

 

 

 

 

 

 

 

 

 

 

 

실행 결과를 살펴보면 이중 포인터 형 변수 pp는 변수 num을 가리키는 포인터 형 변수 p의 주소를 가리키고 있음을 알 수 있다. 따라서 *pp는 p의 주소값이 되고, *p는 num변수의 주소가 된다. 또한 이중 포인터를 이용해 num변수를 바로 접근하기 위해서 **pp를 사용했음을 기억해 두자!

Posted by 김용환 '김용환'

댓글을 달아 주세요

동적 메모리 - 메모리 할당 | c Note 2004/09/07 12:21
http://blog.naver.com/bravedog/100005577911

베열을 이용한 메모리 할당은 프로그램이 실행되기 전부터 이미 메모리의 크기가 정해져 있다. 하지만 필요에 따라 실시가능로 필요한 메모리의 크기를 설정하여 할당해야 할 경우가 있다. 이렇나 경우 피룡한 것이 동적 메모리 할당이다. 동적 메모리 할당은 메모리 할당 함수 malloc 또는 calloc을 이용하여 메모리를 할당하고 해당 메모리에 접근하기 위해서 포인터를 사용한다. 메모리의 크기를 변경하기 위해서는 realloc함수를 사용하고, 마지막으로 할당한 메모리를 제거하기 위해서는 free함수를 사용한다.

 

단 동적 메모리 할당 시에 주의할 점은 사용이 끝난 메모리는 반드시 free함수를 통하여 해제시켜 주어야 한다는 것이다. 그렇지 않으면 프로그램이 종료한 후에도 메모리가 해제되지 않아 사용 가능한 메모리 공간이 줄어들게 된다. 최악의 경우 메모리 부족으로 시스템 오류가 발생할 수도 있다.

 

메모리 할당

 

메모리 할당 함수 malloc과 calloc에 관해서 살펴보자. amlloc과 calloc은 alloc.h또는 stdlib.h에 선언되어 있다. 메모리를 할당한다는 측면에서 두 함수는 유사하나 malloc은 할당된 메모리의 초기화를 하지 않는 반면 calloc은 할당된 메모리를 0으로 초기화를 하는 차이점이 있다.

 

먼저 malloc을 살펴보자. malloc함수의 원형은 다음과 같다.

 

void *malloc(size_t size);

 

malloc은 메모리 힙으로부터 size 바이트 크기의 메모리를 할당하고 그 시작번지의 포인터를 리턴하는 함수이다. 메모리 할당에 성공하였을 경우 할당된 주소의 void 형 포인터가 리턴되며 실패한 경우에는 NULL포인터가 리턴된다.

 

이렇게 리턴된 void 형 포인터를 접근하기 위해서는 앞서 void 형 포인터에서 배운 바와 같이 타입캐스팅이 필요할 수도 있다. 실제로 에전의 C언어는 타입캐스팅이 없으면 경고 메시지를 보내었다. 하지만 현재 ANSI C표준에 의하면 타입캐스팅이 있던 없던 경고를 띄우지 않는다. 따라서 타입캐스팅이 없이 바로 사용할 수 있다.

 

 1  #include <stdio.h>
 2  #include <stdlib.h>         // alloc.h를 써도 무관
 3
 4  int main()
 5  {
 6      int i;
 7      size_t *pEven;
 8
 9      // int 형(2byte) * 10개 = 20 byte
10      pEven = (size_t*)malloc(100);
11
12      // 메모리 할당에 실패했을 경우 프로그램 종료
13      if(!pEven)
14          return EXIT_FAILURE;
15      for(i=0;i<10;i++)
16          pEven[i] = i+1;     // 자연수는 첨자보다 1크다
17
18      printf("짝수 : ");
19      for(i=0;i<10;i++)
20          // 짝수 체크
21          if(pEven[i]%2==0)
22              printf("%d ",pEven[i]);
23      printf("\n");
24
25      // 메모리 해제(반드시)
26      free(pEven);
27
28      return EXIT_SUCCESS;
29  }
30
31  /*---------------------------------------------------------
32   * malloc을 이용하여 메모리를 할당 받을 때에는 필요로 하는
33   * 메모리의 크기를 정확히 알아야 한다.
34   * 하지만 위의 예와 같이 특정 데이터 형을 특정 개수만큼
35   * 받는다면 데이터 형의 크기를 알 수 있는 sizeof연산자를
36   * 사용하여 다음과 같이 사용할 수도 있다.
37   *
38   * int형(2byte) * 10개 = 20byte
39   * pEven = (int*)malloc(10*sizeof(int));
40   *
41   * 동적 메모리 할당에 있어 주의해야 할 점이 또 하나 있다.
42   * 그것은 바로 메모리 할당이 실패하는 경우이다.
43   *
44   * 메모리 할당에 실패했을 경우 프로그램 종료
45   *  if(!pEven)
46   *          return EXIT_FAILURE;
47   *
48   *  만일 메모리 할당에 실패했을 경우 처리하는 구문이 없다면
49   *  프로그램은 마치 메모리가 할당된 것처럼 주소를 접근한다. 
50   *  이러한 경우 프로그램의 실행중 치명적인 오류가 발생한다.
51   *--------------------------------------------------------*/

 

결과화면

 

 

 

 

 

 

 

 

그러면 이번에는 calloc함수를 살펴 보자. 앞에서도 언급하였지만 calloc은 malloc과 달리 할당된 메모리를 0으로 초기화한다고 하였다. 먼저 calloc의 원형을 보도록 하자

 

void *calloc(size_t nitems, size_t size);

 

calloc는 nitems*size 바이트 크기의 메모리를 할당하고, 할당된 메모리를 모두 0으로 초기화하는 함수이다. 리턴값은 malloc과 마찬가지로 성공할 경우 할당된 메모리의 시작주소의 void 형 포인터를, 실패할 경우 NULL 포인터를 리턴한다. 할당 시 초기화가 가능하다는 점에서 malloc 보다 선호하는 경우도 많다.

 

다음 예제 프로그램을 통하여 calloc을 이용한 동젝 메모리 할당을 해보자. 20이하의 자연수 중에서 3의 배수를 출력하는 프로그램이다.

 1  #include <stdio.h>
 2  #include <stdlib.h>         // alloc.h를 써도 무관
 3
 4  int main()
 5  {
 6      int i;
 7      int *pEven;
 8
 9      // int 형(2byte) * 10개 = 20 byte
10      pEven = (int*)calloc(20,sizeof(int));
11
12      // 메모리 할당에 실패했을 경우 프로그램 종료
13      if(!pEven)
14          return EXIT_FAILURE;
15
16      // 초기값 출력
17      printf("초기값\n");
18      for(i=0;i<20;i++)
19          printf("%d ",pEven[i]);     // calloc은 0으로 초기화된다
20
21      for(i=0;i<20;i++)
22          pEven[i] = i+1;             // 자연수는 첨자보다 1크다
23
24      printf("\n20이하의 3의 배수 : \n");
25      for(i=0;i<20;i++)
26          // 3의 배수 체크
27          if(pEven[i]%3==0)
28              printf("%d\n",pEven[i]);
29
30      // 메모리 해제(반드시)
31      free(pEven);
32
33      return EXIT_SUCCESS;
34  }

 

결과 화면

Posted by 김용환 '김용환'

댓글을 달아 주세요

동적 메모리 - 메모리 크기 변경 | c Note 2004/09/07 12:43
http://blog.naver.com/bravedog/100005578511

때로는 필요에 따라 포인터의 위치는 유지하면서 크기를 바꾸고 싶은 경우가 발생한다. 예를 들어 현재 생성되어있는 int형 메모리가 20개 정도인데 데이터가 30개가 들어온다고 가정하자. 이런 경우 기존의 20개 크기의 동적 메모리를 해제하고 다시 30개 크기의 동적 메모리를 생성해야 할까? 만약 그렇다면 매번 크기가 커질 때마다 메모리 해제와 생성을 반복해야 한다. 이런 때에 유용한 함수가 동적 메모리의 크기를 바꿔주는 realloc이다.

 

realloc의 원형은 다음과 같다.

 

void *realloc(void* block, size_t size);

 

여기서 void형 포인터 block에는 크기를 바꿀 메모리에 대한 포인터를, size는 바꿀 메모리의 크기를 말한다.

 

다음 예제 프로그램을 통해서 realloc에 대해 살펴보자. 인원이 총 5명인 한 학급에 대한 평균 성적을 가지고 있다고 가정해 보자. 이때 전학생이 3명 들어 왔을 경우 성적을 관리하기 위한 방법과 다시 4명이 전학간 경우 성적을 관리하기 위한 방법을 간단하게 프로그램으로 해보았다.

 1  #include <stdio.h>
 2  #include <stdlib.h>
 3
 4  void PrintGrade(int *p, int nPerson);               // 총원, 번호, 성적을 출력하는 함수
 5
 6  int main()
 7  {
 8      int i;
 9      int *pGrade = (int*)calloc(5,sizeof(int));      // 메모리 할당
10
11      // 메모리 할당에 실패했을 경우 프로그램 종료
12      if(!pGrade)
13          return EXIT_FAILURE;
14
15      // 성적 대입
16      pGrade[0]=95;
17      pGrade[1]=50;
18      pGrade[2]=65;
19      pGrade[3]=85;
20      pGrade[4]=100;
21
22      PrintGrade(pGrade,5);                           // 5명인 경우
23
24      // 전학생 3명을 포함한 성적 공간 재할당
25      pGrade = (int*)realloc(pGrade,8*sizeof(int));
26
27      pGrade[5]=25;
28      pGrade[6]=70;
29      pGrade[7]=90;
30
31      PrintGrade(pGrade,8);                           // 8명인 경우
32
33      // 전학생 4명을 제외한 성적 공간 재할당
34      pGrade = (int*)realloc(pGrade,4*sizeof(int));
35
36      PrintGrade(pGrade,4);                           // 4명인 경우
37
38      free(pGrade);
39
40      return EXIT_SUCCESS;
41  }
42
43  void PrintGrade(int *p, int nPerson)
44  {
45      int i;
46
47      printf("총원 %d\n",nPerson);
48      printf("==========================================\n");
49      printf("번호 : ");
50      for(i=0;i!=nPerson;++i)
51          printf("%3d ",i+1);
52      printf("\n성적 : ");
53      for(i=0;i!=nPerson;++i)
54          printf("%3d ",p[i]);
55      printf("\n==========================================\n");
56  }
위의 예제를 통해서 알수 있는 것은 realloc으로 동적 메모리의 크기를
변경하더라도 이전에 들어있던 데이터의 값은 변하지 않는다는 것이다.
실행 결과를 보면 5명에서 8명으로 인원이 변하여도 성적이 그대로
출력됨을 알 수 있다.

 

 

 

Posted by 김용환 '김용환'

댓글을 달아 주세요

 
 
Article
Asking "Why?" at Sun Microsystems Laboratories: A Conversation with Director, Glenn Edens
  
 
By Janice J. Heiss, January 2005  

Articles Index

In 1991, Sun Microsystems created Sun Microsystems Laboratories with the express purpose of solving difficult technical problems brought to Sun by customers. Over the years, the results have been impressive. (See sidebar for more details.)

In the fall of 2003, Glenn Edens was named Senior Vice President and Director of Sun Labs. Edens himself has an inspiring record of technological innovation. In 1979, he co-founded Grid Systems Corporation, the company that developed the first laptop computer. He also founded WaveFrame Corporation in 1985, which developed the first all-digital audio workstations for the motion picture, television, and recording industries. From 1992 to 1998, Edens managed the transfer of research results into external product companies at Interval Research Corporation. From 1998 to 2001 he was president of AT&T Strategic Ventures, while also serving as VP of Broadband Technology there. From 2001 to 2003 he was Vice President for Strategic Technology at Hewlett-Packard.

We met with him to learn about the direction he is taking Sun Labs.

questionYou've asked the question, "What follows the Java language? What follows Solaris?" Can you hint at some answers?

answerThose are rallying questions that are designed to give the Labs permission to think about these issues so we can experiment with alternatives. It's not clear that we're actually going to come up with anything better, though we may come up with something better in specific areas. So, for example, there's been a long tradition of work in the Labs challenging Java technology, called Self, which was a totally different model of object-oriented programming, factoring, and reflection.

About Sun Microsystems Laboratories
Sun Microsystems Laboratories claims from 175 to 200 researchers at any given time, with roughly 60% having Ph.D.s. They have a support staff of about 30, along with 20 to 50 interns. Over the years, Sun Labs has created a wealth of books, technical reports, and patents. Funded by Sun's corporate treasury, Sun Labs has offices in Mountain View, California, and Burlington, Massachusetts. Sun Labs technology transfer projects have generated over $2 billion dollars for Sun over the years -- far more if intangibles are accounted for. Since its inception in 1991, the Labs have generated 12% of Sun patents and intellectual property.

To learn more:
http://research.sun.com/about.html
For Sun Labs projects:
http://research.sun.com/projects/index.php
For technical reports
http://research.sun.com/techrep/index.html

The Java platform is a very robust franchise. It's a marketplace. It's a community. It's a programming tool. So we ask questions: What are the alternatives? How do we make the Java runtime smaller? How do we make it faster? How would we change the memory model for the hardware? We're looking at different versions of virtual machine and garbage collection technology. Sometimes in research experiments, we'll change a language feature and experiment with it. And the jury's out as to whether those will ever be significant enough to then launch a JSR process. If you look at the history of programming languages, they don't last forever, because the technology changes, programming styles change, and the good languages last 15 or 20 years.

"We're looking at different versions of virtual machine and garbage collection technology."

- Glenn Edens, Director,
Sun Microsystems Laboratories

So, I would bet money that no matter what happens, whether Sun Labs existed or not, 10 years from now, the Java language will look different than it does today. Humans are really interesting, because we love to build tools, and we learn from that prior building experience to build better tools. So, it's conceivable to me that the Labs could develop an interesting alternative that would be commercially successful. At this point, we're really working in two main areas: How do we make current Java implementations better and how do we make them smaller and faster?

One area of current research explores the link between a Java type object-oriented work load and hardware. In the Labs, the real exciting work isn't about instruction sets. It's about the memory model. So, we have projects like Mayhem and Barcelona, which we don't talk about much, where we're working hard to construct hardware and system software differently. So we're looking at different run time environments. If a large bank or a large customer's main workload is a Java 2 Platform, Enterprise Edition workload, then there's a good chance we could design computers differently to run those workloads better.

We also have a project code-named Squawk, in which we're working on a very compact, high performance Java environment written entirely in the Java language. We're also interested in offering developers in the device world a complete Java stack that doesn't require integration with numerous other system software vendors.

Running but not Managing Sun Labs

questionYou are quoted as saying that you can run a research lab, but you can't manage one. What did you mean by that?

answerA research lab attracts a different personality than a pure product group. And pure academic research and big science attract an even different personality type. So, we're kind of in the middle. My joke about this -- and I get a lot of grief over it, but I still think it's a good metaphor -- is that product organizations are mostly staffed with engineers. And engineers are mostly nerds, who ask: "How are we going to get this done? How does this work? How can we make it better?" How, how, how.

"When managing a set of independent people, you can't tell them what to do."

- Glenn Edens, Director,
Sun Microsystems Laboratories

A research lab tends to consist of hippies, and hippies just ask why. Why, why, why. Why do I have to do it this way? Why should I do that? Why do I need to fill out this form? Why do I have to -- anything. Everything is a question. There is nothing that happens here without an argument. But that's part of our robust culture, and it's the "why" versus the "how". The reason I get in trouble with that analogy is, of course, there are very good engineers in the labs, and there are very good hippies in the product groups.

When managing a set of independent people, you can't tell them what to do. There are only three areas that I directly affect: First, I have some control over the people we hire. Second, I can present questions we ask, bringing in customers, suggesting something to discuss in Sun's Executive Management Group. And third, I can decide what to fund. But that's about it. That's why I say that you can run Sun Labs, but you can't manage it.

Five Kinds of Projects at Sun Labs

questionSun Labs has reinvented the way it works in the last year. You divide projects into five kinds: consulting projects that solve specific customer problems; advanced development projects that support business units with new technology; long-term vision projects; micro-business projects; and community projects.

answerWe decided that we wanted to be crisper about where and how researchers spend their time. So, we perform our role as a teaching organization through consulting with the business units and our customers. We get called on to attend project briefings and hold workshops where we transfer our knowledge. We consult for free, which gives us the freedom to say, "No, we don't want to work on that one." If we charged for consulting, then we're a business. Some of our peer company research labs have gone to that model, but I think that's death for a research lab. Once you start chasing money on a per person basis, you turn yourself into a professional services organization with a lot of Ph.D.s and are no longer a research lab.

Advanced development, the next category, is something we do rarely. But sometimes a business unit will ask us to solve a problem, and we'll take it all the way to a releasable state. That's an expensive proposition for the labs. However, we're taking the Honeycomb project, an integrated storage and server project, very far through this process.

The vision projects are the core of what we do, and we do some interesting things in this area. Each researcher has a project that they pick by themselves and work on for some part of Fridays. They can work on anything they want. The only rule is they have to publish some results. But they get to pick how they spend Friday. Then we have our regular vision research projects, which are funded and evaluated, and we review them and nurture them through to hopefully get transferred to business units. That's probably more than 60% of what we do.


questionIt's interesting that Sun Labs actually launches products through the micro business units with the intent of breaking even, in an effort to keep projects alive.

answerOften we'll have a technology which is a little too small to transfer to a business unit, so we decide to launch the product ourselves. We run these break even, not wanting to lose money on them, but not needing to make money. We want to keep the technology alive and get customer engagement. Real-Time Specification for Java (RTSJ) was headed down that path. We were initially engaging with customers, and then things changed, and we were able to transfer RTSJ to the business unit.

Finally, we have the community projects. And those are everything from open source work to patents, which eventually become public when they get issued. Community projects include chairing conferences, being on program committees, speaking, publishing technical reports and papers. We try to be very interactive with other universities and other conferences, and I think that really helps get that two-way information flow going.

Moving Data at 60 to 100 Times Current Speeds

questionSun Labs recently was awarded a 49.7 million dollar contract from the Defense Advanced Research Projects Agency (DARPA) to help design next-generation supercomputers. This asynchronous design research, advanced by Dr. Ivan Sutherland and Dr. Robert Drost, has already yielded a breakthrough in silicon design with the potential to move data at 60 to 100 times as fast as current top speeds. They are developing Proximity Communication whereby a pair of chips are positioned face-to-face within microns of each other, but not necessarily touching.

answer The proximity IO work at Sun Labs got us the DARPA contract. This is a research project, so there are many questions. It's a substitute for printed circuit boards that allows you to design the hardware and connect chips together differently. The data rates between chips are now as fast as the data rates inside a chip. And so the distance controls the data delay. You can now start putting cache memories and different parts of systems outside in different chips, and the system will run just as fast. This research could change the way we approach silicon for processor design. It might have interesting applications for how switches and routers are built. If we're lucky, this could change how people design high performance computers -- we'll just have to see.

Knowing Customers

questionIt is a given that a lot of the projects at Sun Labs will eventually "fail" -- or perhaps, eventually show up in products in a different form, or become part of human knowledge. In a recent interview on java.sun.com, we talked to Sun's Rick Catell, who spent six years at Xerox PARC watching the invention of brilliant technology that went nowhere, he argued, because the researchers did not know their customers. In doing visionary research, how close should researchers be to customers? Do visionary products fail because researchers are out of touch with customers?

answerOne thing that I find very amusing is that, from the perspective of Xerox, Xerox PARC was a complete success. There was no business model that required Xerox PARC to produce technology that shipped. Xerox PARC was funded because Xerox was afraid that IBM would invent the paperless office; then you wouldn't need Xerox. So, what's paradoxical is that everyone criticizes Xerox PARC, but from their perspective, it was a complete success.

"At the end of the day, the spark of innovation still comes from someone asking, 'Why, why, why, why, why?'"

- Glenn Edens, Director,
Sun Microsystems Laboratories

At Sun Labs, we work hard to make sure that our research staff is grounded in what's happening in the world. What's happening in pop culture? What are kids doing? What's this IM and learning to type with your thumbs about? Because kids, artists, and renegades are going to define how the technology gets used going forward. We bring in speakers and projects and work with other research labs. We work with schools. We bring in a lot of customers. We make sure that for the areas we're working in, we know as much as we can about what other labs are doing and what people's perceived problems are, because they can rarely articulate their real problems. So, a customer might say, "I'm spending too much money on IT." Well, what does that really mean? Does that mean that the money they're spending is not effective? Or does it really mean that it's effective, but they want to spend less? Do they believe it can be cheaper? Is it really a service problem? You have to decompose that.

But at the end of the day, the spark of innovation still comes from someone asking, "Why, why, why, why, why? Why do I have to do it that way? Why is this done this way?" And you cannot replace that spark with any automated or procedural mechanism. It just has never happened. Now, maybe someone will eventually stumble onto the science to "make" innovation occur, which would be quite interesting. What you can do is equip your research lab with as much intelligence, creativity, and knowledge about what's happening in the world as you can. And the more you do that, the more relevant the solutions are going to be.

See Also
Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
If you would like a reply to your comment, please submit your email address:
Note: We may not respond to all submitted comments.

copyright © Sun Microsystems, Inc 
 
Posted by 김용환 '김용환'

댓글을 달아 주세요