기반지식/알고리즘2011. 1. 11. 14:51

Schwarz–Christoffel mapping

From Wikipedia, the free encyclopedia
  (Redirected from Schwarz-Christoffel mapping)

In complex analysis, a Schwarz–Christoffel mapping is a conformal transformation of the upper half-plane onto the interior of a simple polygon. Schwarz–Christoffel mappings are used in potential theory and some of its applications, including minimal surfaces and fluid dynamics. They are named after Elwin Bruno Christoffel andHermann Amandus Schwarz.

Contents

 [hide]

[edit]Definition

Consider a polygon in the complex plane. The Riemann mapping theorem implies that there is a bijective biholomorphic mapping f from the upper half-plane

 \{ \zeta \in \mathbb{C}: \operatorname{Im}\,\zeta > 0 \}

to the interior of the polygon. The function f maps the real axis to the edges of the polygon. If the polygon has interior angles \alpha,\beta,\gamma, \ldots, then this mapping is given by


f(\zeta) = \int^\zeta \frac{K}{(w-a)^{1-(\alpha/\pi)}(w-b)^{1-(\beta/\pi)}(w-c)^{1-(\gamma/\pi)} \cdots} \,\mbox{d}w

where K is a constant, and a < b < c < ... are the values, along the real axis of the ζ plane, of points corresponding to the vertices of the polygon in the z plane. A transformation of this form is called a Schwarz–Christoffel mapping.

It is often convenient to consider the case in which the point at infinity of the ζ plane maps to one of the vertices of the z plane polygon (conventionally the vertex with angle α). If this is done, the first factor in the formula is effectively a constant and may be regarded as being absorbed into the constant K.

[edit]Example

Consider a semi-infinite strip in the z plane. This may be regarded as a limiting form of a triangle with vertices P = 0Q = π i, and R (with R real), as R tends to infinity. Now α = 0 and β = γ = π2 in the limit. Suppose we are looking for the mapping f with f(−1) = Qf(1) = P, and f(∞) = R. Then f is given by

 f(\zeta) = \int^\zeta 
  \frac{K}{(w-1)^{1/2}(w+1)^{1/2}} \,\mbox{d}w. \,

Evaluation of this integral yields

z> = f(ζ) = C + K ar cosh ζ

where C is a (complex) constant of integration. Requiring that f(−1) = Q and f(1) = P gives C = 0 and K = 1. Hence the Schwarz–Christoffel mapping is given by

z = ar cosh ζ

This transformation is sketched below.

Schwarz–Christoffel mapping of the upper half-plane to the semi-infinite strip

[edit]
Other simple mappings

[edit]Triangle

A mapping to a plane triangle with angles \pi a,\, \pi b and π(1 − a − b) is given by

z=f(\zeta)=\int^\zeta \frac{dw}{(w-1)^{1-a} (w+1)^{1-b}}.

[edit]Square

The upper half-plane is mapped to the square by

z=f(\zeta) = \int^\zeta \frac {\mbox{d}w}{\sqrt{w(w^2-1)}}
=\sqrt{2} \, F\left(\sqrt{\zeta+1};\sqrt{2}/2\right).

where F is the incomplete elliptic integral of the first kind.

[edit]General triangle

The upper half-plane is mapped to a triangle with circular arcs for edges by the Schwarz triangle map.

[edit]See also

[edit]References

[edit]Further reading

[edit]External links

'기반지식 > 알고리즘' 카테고리의 다른 글

폴리곤 왜곡 #1  (0) 2011.01.11
Posted by windship
기반지식/알고리즘2011. 1. 11. 14:50

Complex Barycentric Coordinates with Applications to Planar Shape Deformation


Ofir Weber       Mirela Ben-Chen       Craig Gotsman

 


Eurographics 2009 - Computer Graphics Forum 28, 2 (2009)
Gunter Enderle Best Paper Award

 

Image deformation using Point-to-Point complex barycentric coordinates.
Click on the image for hi-res version

 

 
Abstract:
Barycentric coordinates are heavily used in computer graphics applications to generalize a set of given data values. Traditionally, the coordinates are required to satisfy a number of key properties, the first being that they are real and positive. In this paper we relax this requirement, allowing the barycentric coordinates to be complex numbers. This allows us to generate new families of barycentric coordinates, which have some powerful advantages over traditional ones. Applying complex barycentric coordinates to data which is itself complex-valued allows to manipulate functions from the complex plane to itself, which may be interpreted as planar mappings. These mappings are useful in shape and image deformation applications. We use Cauchy뭩 theorem from complex analysis to construct complex barycentric coordinates on (not necessarily convex) polygons, which are shown to be equivalent to planar Green coordinates. These generate conformal mappings from a given source region to a given target region, such that the image of the source region is close to the target region. We then show how to improve the Green coordinates in two ways. The first provides a much better fit to the polygonal target region, and the second allows to generate deformations based on positional constraints, which provide a more intuitive user interface than the conventional cage-based approach. These define two new types of complex barycentric coordinates, which are shown to be very effective in interactive deformation and animation scenarios.
 
Paper - PDF:
      
Supplementary Material - PDF:
      
Video - QuickTime (H264):
      
BibTeX entry:
@article{Complex_Coordinates:2009,
author = {Ofir Weber and Mirela Ben-Chen and Craig Gotsman},
title = {Complex Barycentric Coordinates with Applications to Planar Shape Deformation},
journal = {Computer Graphics Forum (Proceedings of Eurographics)},
volume = {28},
number = {2},
year = {2009},
}
 

More examples:

Comparison of the Point-to-Point Cauchy-Green complex barycentric coordinates and the MLS similarity coordinates.
(left to right) Original image; Deformation using Point-to-Point coordinates; Deformation using MLS coordinates.
The Point-to-Point coordinates better handle control points whose Euclidean distance is small, yet their geodesic distance within the cage is large.
Click on the image for hi-res version

 
 
 
 
 

Deformation of a bird using Szego coordinates. The cage has 21 vertices.
Click on the image for hi-res version

 
 
 
 
 

A giraffe (left), and its deformation (right) using Point-to-point Cauchy-Green coordinates, with 16 control points. The cage has 113 vertices.
Click on the image for hi-res version

Color-coded visualization of one P2P coordinate function. (left to right) Real part; Imaginary part; Absolute value.
Click on the image for hi-res version

 
 
 
 
 

'기반지식 > 알고리즘' 카테고리의 다른 글

폴리곤 왜곡 #2  (0) 2011.01.11
Posted by windship
기반지식/C/C++2010. 7. 1. 19:54
☆ 가상함수와 다형성

#include <iostream.h>
#include <string.h>

class Com
{
public:
virtual void draw()  //<-- 부모 클래스 Com의 원래 함수 draw()를 virtual로 가상함수로 만든다
{
cout << "Com-draw\n";
}
};

/////////////////////////////////////////////////

class Circle:public Com  // <-- 부모 클래스 Com으로부터 상속받음
{
public:
void draw()           // <-- draw() 함수를 원을 그리는 데에 사용한다
{
cout << "원을 그린다\n";
}
};

/////////////////////////////////////////////////

class Rect:public Com   // <-- 부모 클래스 Com으로부터 상속받음
{
public:
void draw()          // <-- draw() 함수를 사각형을 그리는 데에 사용한다
{
cout << "사각형을 그린다\n";
}
};

/////////////////////////////////////////////////

void main()
{
Com *p;
int n;
while(1)
{
cout << "1. Circle  2. Rect  3. Exit\n";
cin >> n;
switch(n)
{
case 1:
p = new Circle();
break;
case 2:
p = new Rect();
break;
default:
return;
}
p->draw();
}
}

  - 순수 가상함수가 포함되어 있는 클래스를 추상(abstract) 클래스라 한다. 
  - 추상 클래스로부터 상속받은 클래스는 반드시 순수 가상함수를 오버라이딩해야 한다. 
  

☆ 예제 2

#include <iostream.h>

class Command
{
public:
virtual void write() = 0;  // 순수 가상 함수
};

////////////////////////////////////////////

class List:public Command
{
void write()
{
cout << "게시판 목록을 출력합니다 \n";
}
};

////////////////////////////////////////////

class Insert:public Command
{
void write()
{
cout << "게시판에 글을 올립니다\n";
}
};

/////////////////////////////////////////////

class Edit:public Command
{
void write()
{
cout << "게시판의 글을 수정합니다\n";
}
};

///////////////////////////////////////////////

/////////////////////////////////////////////

class Delete:public Command
{
void write()
{
cout << "게시판의 글을 삭제합니다\n";
}
};

///////////////////////////////////////////////

void main()
{
int n;
Command *p;

while(1)
{
cout << "1. 추가  2. 삭제  3. 수정  4. 출력  5. 종료\n";
cin >> n;

switch(n)
{
case 1:
p = new Insert;
break;

case 2:
p = new Delete;
break;

case 3:
p = new Edit;
break;

case 4:
p = new List;
break;

default:
return;
}
p->write();
}
}

  - 

☆ 파일 입출력

#include <stdio.h>

void main()
{
        FILE *fp = fopen("c:\\data1.txt", "w"); // w : 쓰기 모드로 파일을 연다. 
                                                                          파일이 없으면 새로 만들고, 있어도 새로 만들어 덮어쓴다.

putc('A', fp);  // putc : 파일에 한글자 출력
putc('B', fp);

fclose(fp);

puts("탐색기에서 확인하세요");
int n;
FILE *fp;

char ch;
while(1)
{
puts("1. 문자 입력 후 Ctrl+Z  2. 파일출력  3. 종료");
scanf("%d", &n);

switch(n)
{
case 1:
fp = fopen("c:\\paper.txt", "a"); // 추가 모드로 파일 열기.
while(1)
{
if((ch=getchar())==EOF)
{
fprintf(fp, "======================\n");   
break;
}
fputc(ch, fp);      // 키보드에서 한글자를 입력받아 파일에 기록.
}
fclose(fp);
break;

case 2:
fp = fopen("c:\\paper.txt", "r"); // 읽기 모드로 파일 열기.
puts("=== paper.txt 파일 읽기 ===");

while(!feof(fp))       // feof : 파일의 끝인가를 검사한다.
{
ch = fgetc(fp);
putchar(ch);
}
puts("\n=== paper.txt 파일 읽기 끝 ===");
fclose(fp);
break;

default:
puts("탐색기에서 파일을 확인하세요");
return;
}
}
}


☆ 파일 입출력(구조체를 사용하는 방법)

#include <iostream>
#include <fstream>

using namespace std;

struct data
{
char name[20];
int age;
char address[20];
};

/*
int main()                                // 파일에 쓰는 부분
{
data man[5]={
{"박문석", 50, "서울"},
{"이순신", 40, "아산"},
{"김유신", 55, "대구"},
{"강감찬", 34, "서울"},
{"을지문덕", 25, "마산"}
};

ofstream fout;

fout.open("c:\\data.txt");
fout.write((char *)man, sizeof(data)*5);
fout.close();

return 0;
}
*/

int main()                         // 파일로부터 읽어오기
{
data man;
ifstream fin;
fin.open("c:\\data.txt");
if(fin.fail())
{
printf("Error: file open error\n");
return 0;
}

cout << " *** 파일에서 읽어온 데이터 ***\n";
cout << "-------------------------------\n";
cout << "이름 나이 주소\n";
cout << "-------------------------------\n";

while(fin.read((char *) &man, sizeof(man)) )
{
cout << man.name << " " << man.age << " " << man.address << endl;
}

fin.close();
return 0;
}

--
Posted by windship
기반지식/C/C++2010. 6. 30. 22:18
☆ 상속과 오버라이딩

#include <iostream.h>
#include <string.h>

class Base
{
protected:
char name[10];
int age;
public:
Base(char *n="이승기", int a=20);
};

Base::Base(char *n, int a):age(a)
{
cout << "Base 생성자 호출\n";
strcpy(name, n);
}

////////////////////////////////////////////////////////////////

class Child:public Base // 부모클래스 Base에서 protected와 public 부분을 물려받아 자식 클래스 Child를
                            // 만든다.
{
public:
Child();
Child(char *n, int a);
void write();
};

Child::Child()
{
cout << "Child 생성자 호출\n";
}

Child::Child(char *n, int a)
{
strcpy(name, n);
age = a;
}

void Child::write()
{
cout << "이름 : " << name << "\n나이 : " << age << endl;
}

////////////////////////////////////////////////////////////////

void main()
{
Child ch;
Child ch2("한예슬", 30);

ch.write();
ch2.write();
}


--
Posted by windship
기반지식/C/C++2010. 6. 30. 21:08
☆ 클래스와 오버로딩, 생성자

#include <iostream.h>
#include <string.h>

class Sales
{
private:
char *pummok;
int su, dan;
public:
Sales(char *p="우유", int s=1, int d=1000);
void Disp() const;
int GetKum() const;
};

Sales::Sales(char *p, int s, int d):su(s), dan(d)
{
pummok = new char[strlen(p)+1];
strcpy(pummok, p);
}

int Sales::GetKum() const
{
return su*dan;
}

// const 함수에서 일반 함수를 호출하지 못한다. 같은 const여야만 호출 가능.
void Sales::Disp() const
{
cout << "품목 : " << pummok << endl;
cout << "수량 : " << su << endl;
cout << "단가 : " << dan << endl;
cout << "총금액 : " << GetKum() << endl;
}

void main()
{
/*
Sales s1;
Sales s2("사과");
Sales s3("포도",5);
Sales s4("수박",3,9000);

s1.Disp();
s2.Disp();
s3.Disp();
s4.Disp();
*/

/*
Sales s[4]={Sales(), Sales("쥬스",7), Sales("오렌지", 3, 1300)};
for(int i=0;i<4;i++)
{
s[i].Disp();
}
*/
Sales *s[3];
s[0]=new Sales();
s[1]=new Sales("apple",3);
s[2]=new Sales("Banana",10,700);

for(int i=0;i<3;i++)
{
s[i]->Disp();
}
}

  - 클래스 Sales 하나를 선언하고 여러가지 형식으로 사용하는 예


☆ 예제 2

#include <iostream.h>
#include <string.h>
#include <iomanip.h>

// static 멤버 변수
// 1. 같은 클래스로 생성되는 모든 인스턴스에서 공유한다.
// 2. 호출할 때 클래스 명을 이용해서 직접 호출 가능
// 3. 초기값은 클래스 밖에서 준다. 안에서는 못 줌.
// 4. this 포인터가 없어서 주소가 없다. static 변수만 접근 가능하다.

class List
{
private:
char name[10]; // 직원 이름
char address[30]; // 집 주소
        static char address2[30];         // 회사 주소
int age; // 직원 나이
public:
List(char *n="", char *add="", int a=0);
void SetHome(char *add);
static void SetOffice(char *add2);
void Disp();
};

char List::address2[30]="강남구 역삼동"; // static 변수 초기화

List::List(char *n, char *add, int a):age(a) // class 내에서 초기화를 못하므로 age의 초기화를 밖에서 해준다.
                                                            // 원래는 함수 안에서 초기화하지만 숫자는 이렇게 바로 해줄수있음.
{
strcpy(name, n);
strcpy(address, add);
}

void List::SetHome(char *add)
{
strcpy(this->address, add);
}

void List::SetOffice(char *add2) // static 함수
{
strcpy(address2, add2);
}

void List::Disp()
{
cout << setw(10) << name << setw(20) << address << setw(20) << List::address2 << setw(7) << age << endl;
}

void write(List *p)
{
for(int i=0;i<3;i++,p++)
{
p->Disp();
}
}

void main()
{
List em[3]={List("박철민", "송파구", 34), List("이승기", "강동구", 21), List("강호동", "서대문구", 34)};

cout << "초기값 출력 \n";

write(em);

cout << "변경된 값 출력(0번 변경해 보기)\n";

em[0].SetHome("하와이");
em[0].SetOffice("스위스");

write(em);
}

  -


☆ 프렌드 함수중복

#include <iostream.h>
#include <string.h>

class Point
{
private:
int x, y;
public:
Point(int x=0, int y=0);
friend void Disp(Point &po); //전역함수를 친구로 지정하는 것. 멤버가 아님!
};

Point::Point(int x, int y)
{
this->x=x;
this->y=y;
}

void Disp(Point &po)
{
cout << "x: " << po.x << ", y=" << po.y << endl;
}

void main()
{
Point a(100, 200);
Disp(a);
}

  - 

Posted by windship
기반지식/C/C++2010. 6. 28. 21:28
☆ 생성자와 소멸자

  - 생성자 : 객체가 생성되는 시점에서 자동으로 수행되는 멤버 함수. 오버로딩이 가능.
  - 소멸자 : 객체가 소멸되는 시점에서 자동으로 호출되는 멤버 함수. 오버로딩 불가.
  - 둘 다 사용자가 호출하는게 아니며 자동적으로 호출된다
  - 리턴값이 없다
  - 함수의 이름이 클래스의 이름과 동일하다
  - 주로 멤버 변수의 초기화나 메모리 할당에 사용된다

#include <iostream.h>
#include <string.h>

class Sinsang
{
private:
//char name[10];   // 클래스 안에서 구체적으로 배열의 길이를 선언해주고 있지만 이것이 안될 경우
char *name;          // 배열을 사용해서 임의의 길이로 문자열을 설정할 수 있도록 한다.
int age;
public:
Sinsang(); //생성자
Sinsang(char *n); // 윗줄과 이름은 똑같지만 파라미터가 틀리므로 오버로딩임.
Sinsang(char *n, int age);

~Sinsang(); //소멸자. 앞에 ~ 가 붙으면 소멸자이다
void Disp() const;
};

Sinsang::Sinsang()
{
// cout << "디폴트 생성자 호출 \n";
name = new char[10]; // 생성자 안에서 배열(문자열)의 길이를 설정한다.
strcpy(name,"디폴트");
age=0;
}

Sinsang::~Sinsang()
{
cout << "소멸자 호출 -> " << name << "\n";
delete name;
}

Sinsang::Sinsang(char *n)
{
// cout << n << "생성자 호출\n";
name = new char[strlen(n)+1]; // 생성자의 호출 타입이 오버로딩으로 달라져 있으므로 
                                                    // 메모리 할당도 다르게 된다. NULL 문자 때문에 문자열 길이 +1이 된다.
strcpy(name,n);
age=0;
}

Sinsang::Sinsang(char *n, int age)
{
name = new char[strlen(n)+1];
strcpy(name,n);
this->age=age;
}

void Sinsang::Disp() const
{
cout << "이름 : " << name << endl;
cout << "나이 : " << age << endl;
}

void main()
{
/*
Sinsang s; // 디폴트 생성자 호출
Sinsang s2("송혜교");
Sinsang s3("한은정",23);
s.Disp();
s2.Disp();
s3.Disp();
*/

Sinsang *s=new Sinsang();
Sinsang *s2=new Sinsang("송혜교");
Sinsang *s3=new Sinsang("한은정",23);

s->Disp();
s2->Disp();
s3->Disp();

delete s3;
delete s2;
delete s;
}


☆ 정적 데이터 멤버



Posted by windship
기반지식/C/C++2010. 6. 25. 19:53
☆ 구조체와 동적 메모리 할당 예제

#include <stdio.h>
#include <malloc.h>

typedef struct Student
{
int no;
char name[10];
int age;

}ST;

void datain(ST *st,int n) // <-- 이 부분 잘 모르겠음... 
{
for(int i=0;i<n;i++,st++)
{
printf("%d번 학생정보 입력\n",i+1);
printf("\t번호 : ");

scanf("%d",&st->no);

printf("\t이름 : ");
scanf("%s",&st->name);

printf("\t나이 : ");
scanf("%d",&st->age);

}
}

void dataout(ST *st, int n)
{
puts("=== 입력결과 출력 ===");
printf("번호\t이름\t나이\n");
for(int i=0;i<n;i++,st++)
{
printf("%-5d%-10s%6d\n",st->no,st->name,st->age);
}
}

void main()
{
int inwon;
ST *st;
printf("입력할 인원수는?");
scanf("%d",&inwon);
st=(ST *)malloc(sizeof(ST)*inwon);

datain(st,inwon);
dataout(st,inwon);

free(st);  // 동적 메모리 해제
}

  - 자료 수를 입력받아 정하고, 그에 맞게 동적 메모리를 할당하여 자료를 입력받고 결과를 출력한다.


☆ 클래스와 접근 지정자

#include <iostream.h>

class Point            // C의 구조체(struct)와 거의 같으나 기본 접근지정자가 private이다.
{

//public:     // <- public으로 할 것이라면 구조체를 쓰는 것과 차이가 없다. (굳이 class를 쓸 필요가 없음)
private:  // <- 안 써줘도 어차피 public임 ㅋㅋ

int x;
int y;

public:       // class 전체는 private이지만 이렇게 필요한 함수 영역에만 public을 지정해 
             // 외부에서 값을 참조할 수 있다.

void SetX(int xx);
void SetY(int yy);

int GetX(); // 아래의 리턴 타입이 int이므로 함수도 int로 선언
{
return x;   // <-- x의 리턴 타입이 int
}

int GetY()
{
return y;
}
};

void Point :: SetX(int xx)
{
x=xx;
}

void Point :: SetY(int yy)
{
y=yy;
}

int Point :: GetX()
{
return x;
}

int Point :: GetY()
{
return y;
}


void main()
{
Point p;

p.SetX(100); 
p.SetY(200);

cout << "X 좌표 : " << p.GetX() << endl;
cout << "Y 좌표 : " << p.GetY() << endl;

p.x=100;  // 이런 식의 직접 접근은 private에서는 불가능
p.y=80;
cout << "X좌표 : " << p.x << endl;
cout << "Y좌표 : " << p.y << endl;

}

  - class는 보통 프로그램 자체에 포함시키지 않고 헤더 파일로 뺀다.
  - 이 경우 #include "파일이름.h"와 같이 인클루드시킨다. (<파일이름.h>가 아님!)
  - class 내부에서 함수가 정의될 경우, 이것 역시 선언만 시키고 class 외부에서 정의할 수 있다.


☆ 클래스와 멤버함수 예제

#include <iostream.h>
#include <string.h>

class Person
{

private:

char name[10];
int kor, eng;

public:
void setName(char *n);
void setScore(int k, int e);
char *getName();  // <-- 요 부분 몰랐음...
int getKor();
int getEng();
int getTot();
};

void Person :: setName(char *n)
{
strcpy(name,n);  // <-- 요 부분도 몰랐음
}

void Person :: setScore(int k, int e)
{
kor = k;
eng = e;
}

char *Person :: getName()   // <-- 문자열을 받는 함수는 기본적으로 포인터로 취급한다고 생각하자.
{
return name;
}

int Person :: getKor()
{
return kor;
}

int Person :: getEng()
{
return eng;
}

int Person :: getTot()
{
return kor + eng;
}


void main()
{
Person p;
p.setName("이수진");
p.setScore(90,100);

cout << "이름 : " << p.getName() << endl;
cout << "국어 : " << p.getKor() << endl;
cout << "영어 : " << p.getEng() << endl;
cout << "총점 : " << p.getTot() << endl;
}

---
Posted by windship
기반지식/C/C++2010. 6. 24. 21:31
☆ 구조체

  - 배열은 같은 타입의 자료들의 묶음
  - 구조체는 다른 타입의 자료들의 묶음


☆ 구조체 예제 1

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

/*
struct Student
{
char name[10];
int age;
int score;
};
*/

typedef struct Student
{
char name[10];
int age;
int score;
}ST;

void display(ST s)
{
printf("Name : %s\n",s.name);
printf("Age : %d\n",s.age);
printf("Score : %d\n",s.score);
}

void datain(ST *sp)   // #1. 아래에서 datain(&t); 로 사용되고 있으므로 sp부분에 포인터라는 것을 명시한다.
                              // 값을 return하지 않아도 포인터이므로 변수에 접근할 수 있다.
{
strcpy(sp->name,"송혜교");
sp->age=30;
sp->score=67;
}

void main0()
{
//struct Student s={"이미연",23,98};
ST s={"이미연",23,98};
ST t;
/*
strcpy(t.name,"한은정");
t.age=11;
t.score=90;
*/

datain(&t);     // t는 주소임. 그러므로 포인터로 받아야 한다 (위쪽 #1)


//printf("Student = \%d Byte\n",sizeof(Student));

//출력
/*
printf("Name : %s\n",s.name);
printf("Age : %d\n",s.age);
printf("Score : %d\n",s.score);
*/
display(s);

puts("==============================");

/*
printf("Name : %s\n",t.name);
printf("Age : %d\n",t.age);
printf("Score : %d\n",t.score);
*/
display(t);
}


☆ 구조체 예제 2

#include <stdio.h>

//레퍼런스 변수 : 같은 기억장소에 붙는 또 하나의 이름(별명). C++에만 있다.
//선언 : 데이터형 &변수명

void main()
{
int a=5;
int &b=a;
int *c=&a;
int d=a;

puts("주소 알아보기");
printf("a의 주소 = %d, b의 주소 = %d, d의 주소 = %d\n",&a,&b,&d);

printf("a=%d,b=%d,*c=%d,d=%d\n",a,b,*c,d);

a=3;

printf("a=%d,b=%d,*c=%d,d=%d\n",a,b,*c,d);

b=1;

printf("a=%d,b=%d,*c=%d,d=%d\n",a,b,*c,d);

d=100;

printf("a=%d,b=%d,*c=%d,d=%d\n",a,b,*c,d);

*c=7;

printf("a=%d,b=%d,*c=%d,d=%d\n",a,b,*c,d);
}


☆ 구조체 예제 3

#include <stdio.h>

void change(int &a)      // call by reference<-- a가 레퍼런스이다. 
{
printf("change a의 주소 : %d\n",&a);
a=5;
}

void change2(int a)     // call by value. 값만 받는 것.
{
printf("change2 a의 주소 : %d\n",&a);
a=10;
}

void main()
{
int a=10;
printf("main a의 주소 : %d\n",&a);
change(a);
change2(a);
printf("a=%d\n",a);
}


☆ 구조체 예제 4

#include <stdio.h>
#include <malloc.h>

void write(int *p)
{
for(int i=0;i<3;i++)
{
printf("p+%d의 값 : %d\n",i,*(p+i));
}
}


void main()
{
// 포인터 변수는 자료형에 상관없이 무조건 4바이트이다.

int *p;

// 동적 메모리 할당
// 포인터 변수명 = (자료형 *)malloc(할당받을 바이트 수);
// 메모리 해제 : free(변수명)

// p = (int *)malloc(sizeof(int)*3);

p=new int[3];    // C++에서 동적 메모리 할당하는 방법. 문법은 new 자료형[갯수]
*p=10;
*(p+1)=15;
*(p+2)=20;

write(p);

// free(p); // 메모리 해제. C에서 하는 방식임(C++은 다름).

delete p; // C++의 메모리 해제. 

write(p);
}


☆ 구조체 예제 5

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

void main()
{
char *s;

// s=(char *)malloc(sizeof(char)*20);

s=new char[20];

strcpy(s,"Happy Virus!!!");

puts(s);

// free(s);

delete s;

puts(s);
}


☆ 구조체 예제 6 

#include <stdio.h>

#include <iostream.h>

typedef struct Sawon
{
int no;
char name[10];
int pay;
int bonus;
int total;
}SA;

/*
SA datain()       // return을 써서 값을 넘길 때에는 이런 식으로 함
{
SA s;
cout<<"사원번호 :";
cin>>s.no;
cout<<"사원이름 :";
cin>>s.name;  
cout<<"월급여 :";
cin>>s.pay;
cout<<"보너스 :";
cin>>s.bonus;

s.total = s.pay + s.bonus;
return s;
};
*/

void datain(SA &s)     // 변수명으로만 받을 경우 void 타입으로 선언하고 이렇게 매개변수를 정의함
{
cout<<"사원번호 :";
cin>>s.no;
cout<<"사원이름 :";
cin>>s.name; 
cout<<"월급여 :";
cin>>s.pay;
cout<<"보너스 :";
cin>>s.bonus;

s.total = s.pay + s.bonus;
}

void dataout(SA *s)
{
cout<<"사원번호 : "<<s->no<<endl;
cout<<"사원명 : "<<s->name<<endl;
cout<<"월급여 : "<<s->pay<<endl;
cout<<"보너스 : "<<s->bonus<<endl;
cout<<"월수령액 : "<<s->total<<endl;
};

void main()
{
SA s;
// s=datain();            // <-- 이렇게 '='로 받는 것은 return을 써서 값을 넘긴다는 뜻.

datain(s); // 변수명으로만 받고 있다. 

dataout(&s);
}


☆ 구조체 예제 7

#include <stdio.h>

typedef struct Sawon
{
int no;
char name[10];
int pay;
int bonus;
int total;
}SA;

// write() 함수를 사용할 때의 선언 및 정의

//void write(SA *sp)      // #1. 아래와 같이 선언할 수도 있다
void write(SA sp[])              // #2. 이렇게 선언할 수도 있다.
{
for(int i=0;i<3;i++)
{
//(sp+i)->total = (sp+i)->pay + (sp+i)->bonus;   // 위에서 #1처럼 했으면 이렇게 사용
sp[i].total = sp[i].pay + sp[i].bonus; // 위 식과 같은 결과를 가진다. #2처럼 하면 이렇게 사용함

printf("%5d%10s%8d%8d%10d\n",
(sp+i)->no, (sp+i)->name, (sp+i)->pay, (sp+i)->bonus, (sp+i)->total);
}
}

void main()
{
SA s[3]={{1,"송혜교",800000,120000},
      {2,"한은정",900000,50000},
      {3,"이승기",1200000,70000}};

/*  #3. 요 부분을 아래의 write()라는 함수로 대체할수도 있음.
for(int i=0;i<3;i++)
{
s[i].total = s[i].pay + s[i].bonus;

printf("%5d%10s%8d%8d%10d\n",
s[i].no, s[i].name, s[i].pay, s[i].bonus, s[i].total);
}
*/

write(s);        // #3 부분을 write()함수로 만들어서 사용하고 있다.
}


☆ 구조체 예제 8

#include <stdio.h>
#define MAX 5

struct record
{
char name[20], id[20];
float kor, eng, avg;
};

typedef struct record RECORD;

void data_in(RECORD st[ ], int size);
void data_out(RECORD st[ ], int size);
void find_avg(RECORD st[ ], int size);

float sum_k=0.0, sum_e=0.0;

void main()
{
RECORD st[MAX];

data_in(st, MAX);
find_avg(st, MAX);
data_out(st, MAX);
}

void data_in(RECORD st[ ], int size)
{
printf("학번|이름|국어|영어\n");
for(int i=0; i<size; i++)
{
scanf("%s", st[i].id);
scanf("%s", st[i].name);
scanf("%f", &st[i].kor);
scanf("%f", &st[i].eng);
}
}

void data_out(RECORD st[ ], int size)
{
printf("학번|이름|국어|영어\n");
for(int i=0; i<size; i++)
{
printf("%s\t", st[i].id);
printf("%s\t", st[i].name);
printf("%.2f\t", st[i].kor);
printf("%.2f\t", st[i].eng);
printf("%.2f\t", st[i].avg);
}

printf("학과 평균\n");
printf("학과 국어 평균 : %.2f\n", sum_k/MAX);
printf("학과 영어 평균 : %.2f\n", sum_e/MAX);
}

void find_avg(RECORD st[ ], int size)
{
for(int i=0; i<size; i++)
{
sum_k += st[i].kor;
sum_e += st[i].eng;
st[i].avg = (st[i].kor + st[i].eng)/2.0;
}
}


Posted by windship
기반지식/C/C++2010. 6. 23. 21:24
☆ 배열과 포인터 예제 1

#include <stdio.h>

void main()
{
int a[5]={3,10,25,30,40};
int *p;

p=a; // p=&a[0] 과 같음

*p=5;
*(p+1)=7;
p++; // p 시작주소를 1칸 이동
*(p+2)=15;
p+=2; // p 시작주소를 2칸 이동
*p=27;


for(int i=0;i<5;i++)
{
printf("a[%d] 의 주소 : %d,%d\n",i,&a[i],p+i);
}

for(i=0;i<5;i++)
{
printf("a[%d] 의 값 : %d,%d\n",i,a[i],*(p+i));
}

}


☆ 배열과 포인터 예제 2

#include <stdio.h>
#define MAX 5

void dataout(int *sp)
{
puts("점수 출력");
for(int i=0;i<MAX;i++)
{
//방법 1
//printf("점수 # %d : %d점\n",i+1,*(sp+i));

//방법 2
//printf("점수 # %d : %d점\n",i+1,*sp++);

//방법 3
printf("점수 # %d : %d점\n",i+1,sp[i]);
}
}

void datain(int *sp)
{
for(int i=0;i<MAX;i++)
{
printf("%d번째 점수 입력 : ",i+1);
scanf("%d",sp+i); // sp가 주소이므로 &는 안 쓴다
}
}

int getsum(int *sp)
{
int temp=0;
for(int i=0;i<MAX;i++)
{
temp+=*(sp+i); //포인터로 배열을 읽어 합계 구하기. sp[i]가 아님!
}
return temp; //값을 리턴하는 시점도 중요함. for문 안에 들어가면 안된다.
}

void main()
{
//int sc[MAX]={67,89,90,56,70};

int sc[MAX],sum;
datain(sc);
dataout(sc);

sum=getsum(sc);
printf("합계 : %d\n",sum);

}


☆ 배열과 포인터 예제 3

#include <stdio.h>

void write(char *s)
{
puts(s);
}


void strupr(char *s)
{
while(*s!='\0')
{
if(*s>='a' && *s<='z')
putchar(*s-32);
else
putchar(*s);
s++;
}
putchar('\n');
}


void strcat(char *a, char *b)
{
while(*a!='\0') // 문자열 a를 NULL문자가 나올 때까지 훑는다
a++;       // *a를 써서 포인터로 받은 문자열 이름은 바로 배열의 첫째칸 변수이기도 하므로 
                            바로 증가시킬 수 있다
while(*b!='\0')
{
*a=*b;
a++;
b++;
}
*a=NULL;
}


void main()
{
char str[]="Have a nice day!!";
char a[20]="apple";
char b[]="banana";

write(str);

strupr(str);
write(str);

strcat(a,b);
write(a);
}


☆ C++에서만 사용할 수 있는 출력양식 (cin, cout)

#include <iostream.h>
#include <iomanip.h>

void main()
{
/*
int age=12;
char name[]="이미자";
double avg=98.7;
*/

int age;
char name[10];
double avg;

cout<<"이름 :";
// cin>>name;
cin.getline(name,10); // <-- 줄단위 입력 가능, 공백도 포함 가능
cout<<"나이 :";
cin>>age;
cout<<"평균 :";
cin>>avg;


// cout<<"이름, 나이, 평균의 순서로 입력하시오\n";
// cin>>name>>age>>avg;

cout<<"이  름 : "<<name<<endl;
cout<<"나  이 : "<<age<<"\n";
cout<<"평  균 : "<<avg<<endl;

cout<<"---------------------------------------------------\n";
cout<<setw(10)<<"이름"<<setw(10)<<"나이"
<<setw(10)<<"평균"<<endl;
cout<<setw(10)<<name<<setw(10)<<age
<<setw(10)<<avg<<endl;
}

ㅇㅇ
Posted by windship
기반지식/C/C++2010. 6. 22. 20:20
☆ 배열과 난수를 사용한 예제

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

void main()
{
int rnd,su,cnt;
char ans;

srand((unsigned)time(NULL));
while(1)
{
cnt=0;
rnd=rand()%100+1; // 1~100 사이에서 난수 발생
while(1)
{
cnt++;
printf("%d회 : ",cnt);
scanf("%d",&su);

if(su>rnd)
printf("\t%d보다 작습니다\n",su);
else if(su<rnd)
printf("\t%d보다 큽니다\n",su);
else
{
printf("\t맞았습니다. 정답은 %d입니다\n",rnd);
printf("계속하시겠습니까? (Y/N):");
fflush(stdin); //바로 입력되어버리지 않게끔 키보드 버퍼의 엔터 입력을 무시
ans=getchar();
if(ans=='y' || ans=='Y')
break;
else
return;
}
if(cnt==10)
{
printf("\t횟수 초과! 맞추지 못했습니다\n");
printf("계속하시겠습니까? (Y/N):");
fflush(stdin);
ans=getchar();
if(ans=='y' || ans=='Y')
break;
else
return;
}
}
}
}

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

void main()
{
int money;
int lotto[6];
srand((unsigned)time(NULL));
printf("로또를 구입할 금액을 입력하세요 : ");
scanf("%d",&money);
for(int n=0;n<money/1000;n++) // 로또는 1회에 천원이므로 1000으로 나누어 몇 회를 뽑을 것인지 계산한다.
{
printf(" %2d 회 : ",n+1);

//로또 1~45 숫자 구하기
for(int i=0;i<6;i++)
{
lotto[i]=rand()%45+1;
//중복체크
for(int j=0;j<i;j++)
{
if(lotto[i]==lotto[j])
{
i--;
break;
}
}
}

//셀렉션 소트로 정렬
int temp=0;
for(i=0;i<5;i++)
{
for(int j=i+1;j<6;j++)
{
if(lotto[i]>lotto[j])
{
temp=lotto[i];
lotto[i]=lotto[j];
lotto[j]=temp;
}

}
}

//출력
for(int a=0;a<6;a++)
{
printf("%4d",lotto[a]);
}
printf("\n");
}
}

☆ 전역변수와 지역변수
#include <stdio.h>

void write()
{
int a=10;
static int b=10;
printf("auto a=%d,static b=%d\n",a,b);
a+=2;
b+=2;
}

void main()
{
for(int i=0;i<5;i++)
write();
}

  - a는 write() 함수 내에서만 사용되는 지역변수이므로 함수 종료시에 함께 소멸된다. 함수 내에 2씩 누적시키는 처리가 있지만 매번 소멸되어 버리기 때문에 값이 누적되지 않는다.
  - b는 프로그램 시작시에 생성되어 프로그램 종료시에 소멸되는 전역변수이다. 따라서 값이 계속 누적된다.

☆ 포인터와 콜바이 어드레스
#include <stdio.h>

void set(int a)
{
printf("set a의 주소 : %d\n",&a);
printf("함수 a의 값 : %d\n",a);
a=20;
}

// call by address의 예

void set2(int *bp)
{
printf("set2 bp의 주소 : %d\n",&bp);
printf("set2에서 *bp의 값 : %d\n",*bp);
*bp=40;
}

void main()
{
int a=10;
printf("main a의 주소 : %d\n",&a);
set(a);
printf("a=%d\n",a);
puts("======================================");
int b=20;
printf("main b의 주소 : %d\n",&b);
set2(&b);
printf("b=%d\n",b);
printf("main에서 b:%d\n",b);
}

#include <stdio.h>

void getsum(int a,int b,int c,int *s) // ※1
{
*s=a+b+c;
}

void main()
{
int sum,kor,eng,mat;  // ※2
kor=25;
eng=100;
mat=70;
getsum(kor,eng,mat,&sum);
printf("세 과목의 합 : %d\n",sum);
}

  - ※1 부분은 함수의 파라미터이므로 ※2 부분의 변수 선언과는 다르다. 변수 선언은 한번에 모두 자료형을 선언할 수 있지만 함수 선언에서는 일일이 자료형을 붙여 줘야 한다.
Posted by windship