2011. 3. 4. 23:23
생성자와 동적할당

#include <iostream>
using std::cout;
using std::cin;
using std::endl;

const int SIZE=20;

class Person
{
 char *name;
 char *phone;
 int age;

public:
 Person(char* _name, char* _phone, int _age);
 void ShowData();

};
Person::Person(char* _name, char* _phone, int _age)
{
 
name = new char[strlen(_name)+1];
 strcpy(name, _name);
 phone = new char[strlen(_phone)+1];
 strcpy(phone, _phone);
 age = _age;
}

void Person::ShowData()
{
 cout<< " name: "<<name<<endl;
 cout<< " phone: " <<phone<<endl;
 cout<< " age: " << age<<endl;
}

int main()
{
 Person p("KIM", "013-113-1113 ", 22);
 p.ShowData();
 return 0;
}


결과적으로 객체 p는 main함수 내에서 생성되었으므로, 스택(stack)영역에 할당이 되겠지만, 생성자 내에서 메모리 공간을 동적을 할당하고 있기 때문에, 멤버 변수 name과 phone이 가리키는 메모리 공간은 힙(heap)이 된다.

=>이러한 형태의 초기화가 주는 이점은 메모리 공간을 효율적으로 사용할 수 있다는 것이다.


!!!문제 :!! 메모리 누수(유출)현상
=>해결 ? 소멸자에서 동적 해체!(delete)

 #include <iostream>
using std::cout;
using std::cin;
using std::endl;

const int SIZE=20;

class Person
{
 char *name;
 char *phone;
 int age;

public:
 Person(char* _name, char* _phone, int _age);
 
~Person();
 void ShowData();

};
Person::Person(char* _name, char* _phone, int _age)
{
 name = new char[strlen(_name)+1];
 strcpy(name, _name);
 phone = new char[strlen(_phone)+1];
 strcpy(phone, _phone);
 age = _age;
}

Person::~Person()
{
 
delete []name;
 delete []phone;
}

void Person::ShowData()
{
 cout<< " name: "<<name<<endl;
 cout<< " phone: " <<phone<<endl;
 cout<< " age: " << age<<endl;
}

int main()
{
 Person p("KIM", "013-113-1113 ", 22);
 p.ShowData();
 return 0;
}

!!!!!생성자 내에서 메모리를 동적 할당하는 경우, 이를 해제하기 위해서 반드시 소멸자를 정의해야 한다.!!




Posted by Triany
2011. 3. 3. 22:07
new : 힙 영역에 메모리 할당
<int 형 데이터 1개 저장>
int * arr = new int;

<길이가 size인 int형 배열 저장>
int * arr = new int[size];

NULL포인터를 리턴하는 new연산자
: 메모리 공간의 여의치 않다면(메모리를 할당만 하고, 적절히 소멸해 주지 않을 경우에 발생) new연산자에 의한 메모리 할당이 실패로 돌아갈 수도 있는 일. 이러한 경우 new 연산자는 NULL 포인터를 리턴..
NULL 포인터란 정수 0을 의미. 매크로로 정의되어 있는 상수 NULL을 사용해도 되고, 직접 0을 사용할 수도 있다.






delete 메모리 해제
<데이터 1개>
delete val;

할당된 메모리 공간이 배열인 경우, 2차 배열이건 3차배열이건 배열을 해제 할 때
delete[] arr;
이라 써주면 된다.


 #include <iostream>

using std::cout;
using std::cin;
using std::endl;

int main(void)
{
 //int형 데이터 1개 저장을 위한 메모리 할당
 int *val = new int;


 //길이가 size인 int형 배열을 위한 메모리 할당.
 int *arr = new int[size];
 ....

delete val;

delete []arr;

}


Posted by Triany
2011. 3. 3. 15:41
레퍼런스 선언
int val =10;
int &ref = val;


포인터를 이용한 Call-By-Reference 
: 포인터를 이용해서 포인터가 가리키는 메모리 공간에 직접 접근이 가능..
[단점] 포인터는 포인터 연산만 가능하기 때문에 잘못된 메모리 접근을 할 가능성이 높다.

 #include <iostream>

using std::cout;
using std::cin;
using std::endl;

void swap(int *a, int *b)
{
 int temp=*a;
//a++; // error.
 *a=*b;
 *b=temp;
}

int main(void)
{
 int val1=10;
 int val2=20;

 cout<< "val1: "<<val1<< "  ";
 cout<< "val2: "<<val2<<endl;

 swap(&val1, &val2);
 cout<< "val1: "<<val1<< "  ";
 cout<< "val2: "<<val2<<endl;
 return 0;
}




레퍼런스를 이용한 Call-By-Reference
:함수내에서 외부에 존재하는 변수에 직접 접근하는 것을 허용하되, 포인터 연산을 못하게 하는 방법.
 =>레퍼런스 사용
->swap함수 내에서는 a와 b라는 이름으로 main함수 내에 선언된 변수 val1과 val2에 직접 접근이 가능하게 된다.

 #include <iostream>

using std::cout;
using std::cin;
using std::endl;

void swap(int &a, int &b)
{
 int temp=a;
 a=b;
 b=temp;
}

int main(void)
{
 int val1=10;
 int val2=20;

 cout<< "val1: "<<val1<< "  ";
 cout<< "val2: "<<val2<<endl;

 swap(val1, val2);
 cout<< "val1: "<<val1<< "  ";
 cout<< "val2: "<<val2<<endl;
 return 0;
}






'Language > C++' 카테고리의 다른 글

복사생성자가 호출되는 시점  (0) 2011.03.07
깊은 복사(Deep Copy) ..(const Person& p) 명시적 정의  (0) 2011.03.07
객체 포인터 배열  (0) 2011.03.04
생성자와 동적할당  (0) 2011.03.04
new / delete  (0) 2011.03.03
Posted by Triany
2011. 3. 2. 23:10
#define으로 시작하는 전처리기 지시자(Preprocessor Directive)
:단순 치환 작업을 요청할 때 사용되는 지시자
(매크로 선언은 문장의 끝을 의미하는 세미콜론(;)을 붙여주지 않는다)
 #include <stdio.h>
 #define PI 3.1415
이때 PI는 마치 상수처럼 사용되고 있다. 따라서 이러한 PI를 매크로 상수라고 한다.

이런 매크로 상수를 이용하면 배열 선언도 가능하다.
 #include <stdio.h>
 #define NUM 10

 int main(void)
{
    int arr[num]={1,2,3,};

   ......
}


매크로를 이용한 함수의 구현
:함수의 기능을 하는 매크로 => 매크로 함수
 #define SQUARE(x)  x*x
 int a = SQUARE(2);
<매크로 함수의 이점>
1. 매크로 함수는 자료형에 독립적이다.
2. 실행 속도가 향상된다.
3. 함수의 크기가 작아야 함.

<매크로 함수의 단점>
함수의 구현이 까다롭고,
디버깅하기 어려우며,
구현하고자 하는 함수의 크기가 크다면 -> 프로그램의 크기가 커지게 됨.


##을 이용하면 토큰을 결합할 수있다.
#define CONCAT(a, b)  a ## b
Posted by Triany
2011. 3. 1. 23:36
의미1) days 라는 이름의 자료형(열거형)
의미2) 상수의 선언

사용하는 이유: 열거형을 사용함으로써 변수가 지니는 값에 의미를 부여할 수 있게 되고, 이에 따라 프로그램의 가독성이 더불어 높아지기 때문!

예제)

#include <stdio.h>
enum days {MON, TUE, WED, THU, FRI, SAT, SUN};

int main(void)
{
 enum days day;
 printf("Input a day(0:Monday ~ 6:Sunday) : ");
 scanf("%d", &day);

 switch(day)
 {
 case MON :
  printf("수영을 하세요.\n");
  break;
  
 case TUE :
  printf("조깅을 하세요.\n");
  break;
  
 case WED :
  printf("축구를 하세요.\n");
  break;
  
 case THU :
  printf("볼링을 하세요.\n");
  break;
  
 case FRI :
  printf("등산을 하세요.\n");
  break;
  
 case SAT :
  printf("탁구을 하세요.\n");
  break;
  
 case SUN :
  printf("원하는걸 하세요.\n");
  break;
 }
 return 0;
}



'Language > C언어' 카테고리의 다른 글

const키워드 기능  (0) 2011.03.07
매크로와 전처리  (0) 2011.03.02
문자열 처리함수  (0) 2011.03.01
문자단위 입.출력 함수(putchar, getchar, fputs, fgets)...etc  (0) 2011.02.28
배열포인터  (0) 2011.02.27
Posted by Triany
2011. 3. 1. 18:51
#include <string.h>

strcpy(str1, str2) :문자열 복사

strncpy(str1, str2, n) : n개만큼 문자열 복사(str2를 str1에)

strcat(str1, str2) :문자열 추가
strncat(str1, str2, n) :n개 만큼 문자열 추가

strcmp(str1, str2) :문자열 비교(같을 시 0을 반환)
strncmp(str1, str2, n)

strstr(str1, str2)
=>원형 : char* strstr(const char *str1, const char *str2)
str1안에 str2 문자열이 있으면 해당 문자열의 위치를 리턴
없으면 0(null)을 리턴



<문자열을 숫자로 변환하는 함수>
#include <stdlib.h>

int atoi(char *ptr); //문자열을 int형 데이터로 변화
long atol(char *ptr); //문자열을 long형 데이터로 변화
double atof(char *str); //문자열을 double형 데이터로 변환


<대소문자의 변환을 처리하는 함수들>
#include <ctypes.h>

int toupper(int c); //소문자를 대문자로
int tolower(int c); //대문자를 소문자로

'Language > C언어' 카테고리의 다른 글

매크로와 전처리  (0) 2011.03.02
열거형(enum) 자료형  (0) 2011.03.01
문자단위 입.출력 함수(putchar, getchar, fputs, fgets)...etc  (0) 2011.02.28
배열포인터  (0) 2011.02.27
포인터와 const키워드  (0) 2011.02.26
Posted by Triany
2011. 2. 28. 19:23
문자 단위 입출력 함수
1) 문자출력함수
 -하나의 문자를 출력할 때 일반적으로 사용하는 함수는 putchar함수와 fputc함수이다.
 int putchar(int c);
 int fputc(int c, FILE* stream);
◇putchar함수 : 함수 호출 시 인자로 전달된 문자를 '표준 출력 스트림(stdout)'으로 출력해주는 역할을 하는 함수. 즉 모니터에다가 하나의 문자를 출력해 주는 함수

◇fputc함수 : 함수 호출 시 인자로 전달된 문자를 '표준 출력 스트림(stdout)'으로 출력해주는 역할을 하는 함수. 즉 모니터에다가 하나의 문자를 출력해 주는 함수 +.. 문자를 출력할 스트림을 지정할 수 있다!(모니터뿐 아니라 파일에도 문자를 출력(저장)할 수 있는 함수)
fputc 함수의 두 번째 인자 stream은 문자를 출력할 스트림을 지정하기 위해서 사용된다. 따라서 이 인자에다가 표준 출력 스트림을 의미하는 'stdout'을 인자로 전달하게 되면 putchar함수와 완전히 동일한 함수가 된다. fputc함수는 파일 입.출력에서 주로 사용하게 된다.


※참고 : 오류 발생 시 반환되는 EOF의 실제 값을 -1이다.


2)문자 입력 함수
하나의 문자를 입력받을 때 일반적으로 사용하는 함수는 getchar함수와 fgetc함수이다.
 int getchar(void);
 int fgetc(FILE* stream);

◇getchar 함수: '표준 입력 스트림(stdin)'으로부터 한 문자를 입력받아서 반환해 주는 함수이다. 따라서 키보드로부터 하나의 문자를 입력받는 함수라고 할 수 있다.

◇fgetc함수:'표준 입력 스트림(stdin)'으로부터 한 문자를 입력받아서 반환해 주는 함수이다. 따라서 키보드로부터 하나의 문자를 입력받는 함수라고 할 수 있다.+.. 문자를 입력받을 스트림을 지정할 수 있다는 특징.(fgetc함수를 이용하면 키보드뿐만 아니라 파일로부터도 데이터를 입력받을 수 있다.)


#include <stdio.h>

int main()
{
 char ch=0;
 while(ch != 'q')
 {
  ch=getchar();    //fgetc(stdin)와 같다.
  putchar(ch);     //fputc(ch, stdout)와 같다.
 }

 return 0;
}



3)EOF에 대해서...
 오류 발생 혹은 파일의 끝에 도달했을 경우 EOF를 리턴.
 EOF가 실제로 지니고 있는 값을 -1이다.
 오류발생시 반환 + (fgetc나 getchar 함수가 파일의 끝에 도달하는 경우에도 EOF가 반환)
 getchar : 키보드로부터 Ctrl-Z키를 입력하는 경우에 EOF를 반환

 #include <stdio.h>

int main()
{
 char ch=0;
 while(ch != EOF)
 {
  ch=getchar();
  putchar(ch);
 }
 printf("program 종료 \n");

 return 0;
}



문자열 단위 입.출력함수
1)문자열 출력 함수
하나의 문자열을 출력할 때 일반적으로 사용하는 함수는 puts 함수와 fputs함수이다.
 int puts(const char* s);
 int fputs(const char* s, FILE* stream);
puts 함수: 문자열을 표준 출력 스트림(stdout)으로 출력하기 위해 사용하는 함수이다. 인자로 전달되는 포인터는 문자열을 가리키고 있어야 한다.
문자열을 출력한 다음에 자동으로 줄을 바꿔준다.

fputs함수 : 문자열을 표준 출력 스트림(stdout)으로 출력하기 위해 사용하는 함수이다. 인자로 전달되는 포인터는 문자열을 가리키고 있어야 한다. +.. 문자열을 출력할 스트림을 선택할 수 있다.
문자열을 출력한 다음에 자동으로 줄을 바꿔주지 않는다.

 #include <stdio.h>

int main()
{
 fputs("fputs 함수에 의한 출력, ", stdout);
 fputs("I Love Linux ", stdout);

 fputs("\n", stdout); //한 줄 건너 뛰기 위해서

 puts("fputs 함수에 의한 출력, ");
 puts("I Love Linux ");
}
 



2) 문자열 입력 함수
하나의 문자열을 입력받을 때 일반적으로 사용하는 함수는 gets함수와 fgets함수이다.
 char* gets(char* s);
 char* fgets(char* s, int n, FILE* stream);
◇gets 함수: 문자열을 입력받는 함수이다. 우선 입력받을 문자열을 저장하기 위한 배열은 선언한 다음, 배열의 시작 주소(배열이름이 배열의 시작주소이다)를 인자로 전달하면서 gets 함수를 호출하게 되면 표준 입력 스트림(키보드)로부터 데이터를 입력받는다.
(하지만 이 함수는 자제해야 함. 미리 할당해 놓은 배열의 크기보다도 큰 길이의 문자열이 들어오게 되면 배열의 Overflow가 발생)

◇fgets함수 :gets함수의 잠재적 위험성 때문에 실제 프로그램에서는 fgets함수만을 사용. fgets함수의 두번째 인자 n은 입력받을 수 있는 최대 문자열의 길이를 나타낸다. 따라서 문자열을 입력받을 배열의 길이를 인자로 전달하면, 그 이상의 문자를 읽어들이는 일은 발생하지 않는다. 마지막으로 세 번째 인자 stream은 입력을 받을 스트림을 지정하기 위해 사용된다.

 #include <stdio.h>

int main()
{
 char str[10];

 fputs("문자열을 입력 하세요: ", stdout);
 fgets(str, sizeof(str), stdin);

 fputs("입력된 문자열: ", stdout);
 fputs(str, stdout);

 return 0;
}
 

※주의 : 배열의 길이가 10이기 때문에 fgets함수 호출시 두 번째 인자(n)에도 10을 전달하였음에도 불구하고 총 9개의 문자가 입력된다. 이는 fgets함수가 문자열을 입력받는 함수이기 때문이다. C에서 문자열이 되기 위한 기본조건은 끝에 반드시 NULL 문자가 들어가야 한다.
(즉 fgets 함수는 입력받을 수 있는 최대 문자열의 길이 n을 초과하는 문자열이 입력되는 경우에는 n-1개 까지의 문자만 입력을 받고, 마지막에 NULL 문자를 삽입해 준다.)


'Language > C언어' 카테고리의 다른 글

열거형(enum) 자료형  (0) 2011.03.01
문자열 처리함수  (0) 2011.03.01
배열포인터  (0) 2011.02.27
포인터와 const키워드  (0) 2011.02.26
scanf 함수 호출 시 &를 붙이는 이유  (0) 2011.02.26
Posted by Triany
2011. 2. 27. 02:09

int (*pArr)[4];
: int arr1[2][4], int arr2[3][4]와 같은 배열을 가리킬 수 있는 포인터
이렇듯 배열을 가리킬 수 있다고 해서 배열 포인터라 한다.

void show_data(int (*ptr)[4], int a);
    ==
void show_data(int ptr[][4], int a);  <= 함수의 매개변수 선언시에만 가능

#include <stdio.h>

void show_data(int (*ptr)[4], int a);
int main(void)
{
 int arr1[2][4]={1, 2, 3, 4, 5, 6, 7, 8};
 int arr2[3][4]={{1}, {2}, {3}};

 show_data(arr1, 2);
 show_data(arr2, 3);
 
 return 0;
}

void show_data(int (*ptr)[4], int a)
{
 int i, j;
 printf("-------Start Print----------\n");
 for(i=0; i<a; i++)
 {
  for(j=0; j<4; j++)
   printf("%d ", ptr[i][j]);
  printf("\n");

 }

}





☆int (*pArr)[4] 와 int* pArr[4]의 차이점☆
int (*pArr)[4]는 배열을 가리키는 포!인!터이다. (배열포인터)
  int형 변수를 요소로 지니고 포인터 연산시 4칸씩 이동하는 2차원 배열을 가리키는 포인터이다.


int* pArr[4]는 배!열!이다.(포인터배열).
  int형 변수의 주소 값 4개를 저장할 수 있는 배열이다.

Posted by Triany
2011. 2. 26. 22:19

win7 운영체제를 깔고난 이후, 자리를 비웠다 오면 자주 자동 재부팅이 일어났다.
고민하던 중, 방법을 찾게 되었다.


1)예약된 자동업데이트 시 자동재부팅 기능 설정안함 

 window키 + R 을 눌러 실행 창을 뜨게 한다.
 gpedit.msc 를 입력한다.


로컬 그룹 정책 편집기에서
[컴퓨터구성]-[관리템플릿]-[windows구성요소]-[windows update]로 들어가
예약된 자동 업데이트 설치 시 로그인한 사용자로 자동 다시시작 안함을 더블릭하여 사용으로 바꿔준다.

사용으로 바꾸고 확인을 눌러주면 OK



2)오류시 자동 재부팅 기능 해제
내컴퓨터-속성-관리-고급시스템설정-고급에 들어간다.

시작 및 복구에서 설정을 클릭해 준후, 시스템 오류시 자동으로 다시 시작 체크박스를 해지해 준다.

Posted by Triany
2011. 2. 26. 20:23
1) 포인터가 가리키는 변수의 상수화

  int a = 10;
  const int*p = &a;
  *p = 30; //error!!
  a = 30; //ok
포인터 p가 가리키는 변수를 상수화 하겠다는 뜻. 즉 포인터 p가 가리키는 변수의 값을 못 바꾸게 하겠다는 뜻이다.
포인터 p를 통해서 변수 a의 값을 변경하는 것만 막는 것.


2)포인터 상수화
  int a = 10;
  int b = 20;
  int* const p = &a;
  p = &b; //error
  *p = 30; //ok
포인터 자체가 상수화 된것. 즉 포인터 p가 지니는 주소값을 변경할 수 없다는 뜻이다.


3)포인터 상수화 + 포인터가 가리키는 데이터도 상수화
  int a = 10;
  int b = 20;
   const int* const p = &a;
  p = &b; //error
  *p = 30; //error
Posted by Triany