2016년 2월 23일 화요일

C언어 메모리 조작 함수 : memcpy, memmove

메모리 조작 함수 memcpy, memmove 는 strcpy와 흡사 하다.

헤더는 include<memmory.h> or string.h 이다.

memcpy(복사될 문자열 B+시작할 주소, 복사할 문자열 A+시작할 주소, 복사될 메모리의 크기)
memmove(이동될 문자열 B+시작할 주소,이동할 문자열 B+시작할 주소, 이동 메모리의 크기)

결과적으로 memcpy, memmove는 문자열을 복사한다는 면에서 같다.

#include<stdio.h>
#include<string.h>
int main()
{
 char A[] = "I love her";
 char B[] = "I feel you";
 int C[] = {1,2,3,4,5};
 int D[] = {6,7,8,9,10,11};
 int i;

 printf("원래 문장 A : %s \n",A);
 printf("원래 문장 B : %s \n",B);
 printf("원래 문장 C :");
 for(i=0;i<5;i++)
 {
  printf("%d ",C[i]);
 }
 printf("\n");
 printf("원래 문장 D :");
 for(i=0;i<6;i++)
 {
  printf("%d ", D[i]);
 }
 printf("\n");


 memcpy(B+7,A+7,3);
 memmove(D,C,sizeof(int)*5);       //D[1]과 C[3]을 하고 싶다면 &D[1],&C[3],4 를 하면 된다.

 printf("바뀐 후 A : %s \n",A);
 printf("바뀐 후 B : %s \n",B);
 printf("바뀐 후 C :");
 for(i=0;i<5;i++)
 {
  printf("%d ",C[i]);
 }
 printf("\n");
 printf("바뀐 후 D :");
 for(i=0;i<6;i++)
 {
  printf("%d ", D[i]);
 }
 printf("\n");
}

아래 그림처럼  A[7] 부터 3개가 B[7] 부분으로 복사 되었고
C를 D에 이동시켰다.
이렇게 결과는 둘이 같다.



C언어 문자열 비교 : strcmp 함수

문자열을 비교하는 함수 strcmp 가 있다.
헤더는 include<string.h>
 
  •  strcmp(문자열 A, 문자열 B) 는 A와 B를 비교하는 것이다. 
    A>B 일때 양수
    A=B 일때 '0'
    A<B 일때 음수로 나온다.
 
이때 비교는 아스키 코드값으로 비교한다.
 만약 char A[4]: "abc" , char B[4] : "def" 면  A<B 이다.
 
#include<stdio.h>
int main()
{1
     char A[] = "Happy day";
     char B[] = "Happy day";
    
    if(A == B)
     {
         printf("두 문자열은 같다. \n");
      }
     else
      {
         printf("두 문자열은 같지 않다. \n");
       }
}
 
이렇게 되면 두 문자열은 같다고 나오지 않는다.
왜냐하면 if(A == B)는 주소값을 비교하는 것이기 때문이다.
문자열 A와 B는 주소값이 다르다.
 
그래서 문자열을 비교해주는 함수 strcmp가 필요한 것이다.
 
#include<stdio.h>
#include<string.h>
 
int main()
{
   char A[] = "Happy day";
   char B[] = "Happy day";
 
   if(strcmp(A,B) == 0)
   {
         printf("A와 B는 같은 문자열이다.\n");
    }
    else
           printf("A와 B는 같은 문자열이 아니다. \n");
}
 
이렇게 해야 같은 문자열이라는 경우가 나온다.

2016년 2월 20일 토요일

C언어 선택정렬 실습

배열을 정렬하는 방법은 여러가지가 있다.
그 중 선택 정렬이라는 것은 배열의 자리를 하나씩 비교하면서 자리를 바꾼다.
 오름차순으로 또는 내림차순으로 정렬하게 해주는 것이다.

우선 4개를 정한 상태에서 실습이다.
#include<stdio.h>
int main()
{
 int aa[4]={75,34,39,80};
 int i,k,change;

 printf("바뀌기전 %d %d %d %d \n",aa[0],aa[1],aa[2],aa[3]);
 for(i=0;i<4;i++)
  for(k=i+1;k<4;k++)
  {
   if(aa[i] > aa[k])
   {
    change = aa[i];
    aa[i] = aa[k];
    aa[k] = change;
   }
 
  }
 
  printf("바뀐후 %d %d %d %d \n", aa[0],aa[1],aa[2],aa[3]);
}
이렇게 예를 들수 있다.
좀더 심화로 포인터와 동적메모리 함수를 이용한 예를 보겠다.

#include<stdio.h>
#include<malloc.h>
int main()
{
 int *p;
 int s;
 int j,i,k,change;
 printf("정렬할 숫자의 갯수를 입력하세요.:");
 scanf_s("%d",&s);
 p=(int*)malloc(4*s);
 printf("정렬할 수를 입력하세요. :");
 for(j=0;j<s;j++)
 {
  scanf("%d",&*(p+j));
 }
 printf("정렬전 :");
 for(j=0;j<s;j++)
 {
  printf(" %d",*(p+j));
 }
 printf("\n");
 for(i=0;i<s;i++)
  for(k=i+1;k<s;k++)
  {
   if(*(p+i) > *(p+k))
   {
    change = *(p+i);
    *(p+i) = *(p+k);
    *(p+k) = change;
   }
 
  }
 printf("정렬 후 :");
  for(j=0;j<s;j++)
 {
  printf(" %d",*(p+j));
 }
 printf("\n");
}

이렇게 되면 사용자가 입력을 마음대로 정할 수도 있다.

2016년 2월 14일 일요일

C언어 열거형, 공용체

열거형 공용체 둘다 구조체와 사용법은 비슷하나 활용이 조금다르다.
구조체와 같이 많이 쓰는 문법은아니다.

열거형은 변수를 지정하면  변수들이 차례대로 0부터 지정이 되는 것이다.
사용법은
enum 열거형이름 { 변수1,변수2,변수3,...};

enum 열거형 이름 열거형 변수;

ex)
#include<stdio.h>
int main()
{
 enum aa{ 장미, 수국, 안개꽃};
 enum aa b;
 int c;
 printf("0~2을 입력하세요:");
 scanf("%d",&c);
 b = c;
 if(b == 장미)
  printf("장미입니다. \n", b);
 else if(b == 수국)
  printf("수국입니다. \n",b);
 else
  printf("안개꽃 입니다.\n",b);
}

공용체는 구초제와 거의 흡사하지만 메모리를 같이 쓰기 때문에 정수형과 문자형 변수를 같이 쓰면 겹쳐져서 오류가 날 수 있다.

공용체는
union 공용체형이름{
         데이터형 변수;
         데이터형  변수;
};

구조체와 같이 쓰는 방식은 같다.

2016년 2월 12일 금요일

C언어 고급포인터: 동적메모리 함수

배열을 사용자가 사용할 때 입력할 개수를 정해야 할 때가 있다.
배열의 메모리10000개 잡아놨을 때 aa[10000] 이중에 5개만 쓸 경우 나머지 9995개는 쓸데 없이 낭비가 되는 것이다. 메모리를 적절하게 사용하기위해
메모리를 미리 잡아두지않고, 필요할 때마다 확보하는 것을 동적메모리 확보라고 한다. 이때 사용하는 함수가 malloc()이다.  이때 헤더는 #include<malloc.h>이다.
malloc는
포인터 변수 = ( 포인터 변수의 데이터형*)malloc(포인터 변수의 데이터형 크키 * 필요한 크기)
ex)
include<stdio.h>
include<malloc.h>

int main()
{
     int *p;
     int i,hap=0;
     int cnt;

     printf("입력할 개수는?");
     scanf("%d",&cnt);  
    
     p=(int*)malloc(4*cnt);  // 데이터형의 크기를 모를시 4대신에 sizeof(int)를 사용 가능
    
     for(i=0;i<cnt;i++)
     {
          printf("%d 번째 숫자는?",i+1);
          scanf("%d",&*(p+i));
     }
    
     for(i=0;i<cnt;i++)
          hap= hap+ (p+i);

     printf("입력 숫자의 합 ==> %d \n", hap);

     free(p);
}
출처 : c언어 기초   우재남 저자   한빛미디어 출판사
이렇게 메모리를 유동적으로 만들 수 있다.

또한  malloc()를 사용 했다면 free() 함수도 같이 써서 사용 했던 메모리를 다시 운영체제에 반납한다. free()는 널(null)값을 넣는다는 뜻이다.

이외에도 calloc(), realloc()함수를 사용하는 경우도 있다.
malloc() 함수는 메모리를 확보한 후 초기화를 하지 않기 때문에 최초에는 쓰레기값이 들어가 있다. 처음부터 0으로 초기화된 메모리를 확보하고 싶다면 calloc()함수를 사용한다.

realloc()함수는 최초로 확보한 메모리 크기를 변경 할 때 사용한다.
포인터 변수 =(포인터 변수의 데이터형*)realloc(기본 포인터,포인터 변수의 데이터형 크기 * 필요한 크기)

realloc()는 반복문에 사용하여 계속 필요한 크기를 변경 할 수 있다. malloc or calloc은 한 번 정해지면 바꿀 수 없다.

2016년 2월 10일 수요일

C언어 STDOUT, STDIN 란

데이터 이동 수단인 stream
c언어에서 기본적으로 제공하는 스트림은 우리가 컴퓨터에 모니터, 마우스, 키보드등의 연결되어 있지 않은 개체들을 연결시켜주는 다리이다.

stdin 표준 입력 스트림
stdout 표준 출력 스트림
stderr표준 에러 스트림이다.

에러스트림과 표준 출력 스트림은 자세히 보면 모니터로 출력이 이뤄진다는 점에서 둘이 차이가 없다. 하지만 표준 에러 스트림의 출력 대상을 변경시킬 수 있어서, stdout 와 stderr의 용도를 구분할 수 있다.
scanf, printf 함수들도 표준 입출력 스트림을 사용한 함수들이다.

일반적으로 콘솔은 키보드와 모니터를의미하는데 콘솔 입풀력을 위한 스트림은 자동으로 생성되고 프로그램이 종료된면 자동으로 소멸된다.

서식화된 입출력 함수 printf, scanf 말고

문자열 입출력 함수
gets 표준입력장치(키보드)로부터 문자열을 입력 받는다. 숫자를 입력해도 문자열로 인식
puts 표준출력장치(모니터)에 문자열을 출력한다.

ex)
char aa[20];
gets(aa);
puts(aa);

문자 입출력 함수
셋 모두 키보드를 통해 문자 하나 입력 받는다.
getch() : 키보드를 통해 문자 하나 입력 받고 입력한 내용을 화면에 보여주지 않는다.
getche() : 입력한 내용을 화면에 보여준다.
getchar() : 사용자가 키보드로 엔터키를 누를 떄까지 입력한 것을 메모리에 모두 저장해 놓는다. 그중에 한 문자만 꺼낸다.

putchar, putch 표준출력장치(모니터)에 문자 하나를 출력한다.

2016년 2월 6일 토요일

C언어 rand 함수

 야구게임을 만들면서
난수 rand 함수, 실행할때마다 다르게 난수를 만들기위해 srand time함수를 새로 배웠다.
rand 함수를 쓰려면 헤더파일 stdlib.h를 써야하고
srand time을 쓰려면 헤더파일 time.h가 필요하다.
rand()%n는 0~n-1까지 범위를 정해주는 것이다.
만약 앞의 범위를 정해주고 싶다면
 정수+rand()%n;
srand(time(NULL)); // NULL은 대문자로 해야한다.
 

goto 함수 : 지정한 곳으로 향하게 하는 것이다.
ex)
mygoto :
printf(" ~~~~~~~~~~");
나오고 나중에 goto mygoto; 로하면 아래로 순차적으로 가는게 아니라 다시 위로 간다.


주소 값의 저장을 목적으로 선언되는 포인터 변수
포인터 변수 선언 : 자료형 * 변수   EX) int *AA; 
배열의 주소를 포인터 변수에 초기화 :
 int AA[10];
int *A = &AA[0]; or int *A = AA;
*A는 A메모리 자리에 실제 값이며 맨앞의 값이 주소값이다.
&AA = A 주소값
AA[0] = *A 실제값이다.




C언어로 스도쿠 만들기 2 : 포인터 활용

이전글은 오직 배열로 스도쿠를 코딩 했는데 조금 응용해서 포인터 변수를 이용해보았다.



#include<stdio.h>
int main()
{
    int i,j;
 int k=0;
 int A[9][9]= {
  {2,0,5,0,0,7,0,0,6},
  {4,0,0,9,6,0,0,2,0},
  {0,0,0,0,8,0,0,4,5},
  {9,8,0,0,7,4,0,0,0},
  {5,7,0,8,0,2,0,6,9},
  {0,0,0,6,3,0,0,5,7},
  {7,5,0,0,2,0,0,0,0},
  {0,6,0,0,5,1,0,0,2},
  {3,0,0,4,0,0,5,0,8}
 };
 int *AA= &A[0][0];   // 포인터 변수 선언 및 초기화
 int B[9][9] = {
  {2,3,5,1,4,7,9,8,6},
  {4,1,8,9,6,5,7,2,3},
  {6,9,7,2,8,3,1,4,5},
  {9,8,6,5,7,4,2,3,1},
  {5,7,3,8,1,2,4,6,9},
  {1,4,2,6,3,9,8,5,7},
  {7,5,9,3,2,8,6,1,4},
  {8,6,4,7,5,1,3,9,2},
  {3,2,1,4,9,6,5,7,8}
 };
 int *BB=&B[0][0];
 int c[9][9];
 int *CC=&c[0][0];

 printf("아래에 0에 들어가는 알맞는 자리를 입력하세요.\n");
 for(i=0;i<9;i++)
 {
  for(j=0;j<9;j++)
  {
   printf("%2d",*(AA+k));
   k++;
  }
  printf("\n");
 }
 mygoto :
 printf("스도쿠의 모든 숫자를 입력하세요\n");
 k=0;
 do{
  for(j=0;j<9;j++)
  {
  scanf("%d %d %d %d %d %d %d %d %d",&*(CC+k),&*(CC+k+1),&*(CC+k+2),&*(CC+k+3),&*(CC+k+4),&*(CC+k+5),&*(CC+k+6),&*(CC+k+7),&*(CC+k+8));  //*(CC+k) 는 메모리에 할당된 실제값을 의미한다.
  k+=9;
  }
k=0;
 for(i=0;i<9;i++)
 {
  for(j=0;j<9;j++)
  {
   if(*(CC+k) != *(BB+k))
   {
    printf("틀렸습니다. 다시 입력하세요 \n");
 goto mygoto;
   }
   k++;
  }
 }
 }while(*(CC+80) != *(BB+80));
 printf(" 정답! 게임종료\n");

}

c언어 스도쿠 만들기 : 배열

일주일만에 스도쿠에 도전을 한다.
스도쿠를 예전에 군대에 있을 때 친구가 하는 걸 보고 관심이 생겨 한 번 해본적이 있었다.
룰은 간단했지만 굉장히 어려워서 금세 포기하고 말았다. 그런데 그런 스도쿠를 만들다니 정말 아이러니했다.

http://navercast.naver.com/contents.nhn?rid=22&contents_id=1127 그림 발췌


스도쿠는 위 그림처럼  9x9칸으로 구성 되어 있고 3x3 칸 9개로 볼 수 있다.
3x3 안에는 1~9까지 겹치지 않게 들어가고 가로줄 9개에 1~9까지 겹치지 않게 모두 들어가있다. 또한 세로줄 마찬가지이다.


#include<stdio.h>
int main()
{
    int i,j;
 int A[9][9]= {
  {2,0,5,0,0,7,0,0,6},
  {4,0,0,9,6,0,0,2,0},
  {0,0,0,0,8,0,0,4,5},
  {9,8,0,0,7,4,0,0,0},
  {5,7,0,8,0,2,0,6,9},
  {0,0,0,6,3,0,0,5,7},
  {7,5,0,0,2,0,0,0,0},
  {0,6,0,0,5,1,0,0,2},
  {3,0,0,4,0,0,5,0,8}
 };
 int B[9][9] = {
  {2,3,5,1,4,7,9,8,6},
  {4,1,8,9,6,5,7,2,3},
  {6,9,7,2,8,3,1,4,5},
  {9,8,6,5,7,4,2,3,1},
  {5,7,3,8,1,2,4,6,9},
  {1,4,2,6,3,9,8,5,7},
  {7,5,9,3,2,8,6,1,4},
  {8,6,4,7,5,1,3,9,2},
  {3,2,1,4,9,6,5,7,8}
 };
 int c[9][9];

 printf("아래에 0에 들어가는 알맞는 자리를 입력하세요.\n");
 for(i=0;i<9;i++)
 {
  for(j=0;j<9;j++)
  {
   printf("%2d",A[i][j]);
  }
  printf("\n");
 }
 mygoto :
 printf("스도쿠의 모든 숫자를 입력하세요\n");
 do{
 for(i=0;i<9;i++)
 {
  scanf_s("%d %d %d %d %d %d %d %d %d",&c[i][0],&c[i][1],&c[i][2],&c[i][3],&c[i][4],&c[i][5],&c[i][6],&c[i][7],&c[i][8]);
 }
 for(i=0;i<9;i++)
  for(j=0;j<9;j++)
  {
   if(c[i][j] != B[i][j])
   {
    printf("틀렸습니다. 다시 입력하세요 \n");
 goto mygoto;            // 여기에  continue를 해서 반복문 처음으로 보냈었는데 그랬더니 9번 틀리면 9번 틀렸습니다. 다시 입력하세요 라고 나오고 맞는 줄은 정답 게임종료라고 계속 떠서 goto로 반복문 앞 으로 보냈다.
   }
  }

 }while(c[8][8] != B[8][8]);
 printf(" 정답! 게임종료\n");