포인터는 메모리의 주소값을 저장하는 변수이다.


[ 기본형태 : 포인터 타입* 포인터명 ]


Pointer, 가르키는 지시자인 포인터는 DataType 명시하는 대신, 자신이 가르킬 변수의 DataType을 명시한다.



다른 변수들은 선언 시 DataType에 의해 변수의 크기가 결정되는 반면,


포인터는 주소값을 저장하기 때문에, DataType과는 상관없이 항상 4byte의 크기를 유지한다.


<예시>




<결과값>









[포인터 문제]


다음 값이 어떻게 찍히는 지 생각해 보시오.



































= 답 







==문제풀이



printf("%d", *ptr++);        printf("%d", *ptr);


 : 포인터명 뒤에 붙은 ++은 증감연산자중에서 후 중감연산자로, 


  printf함수를 먼저 실행한 후에, 해당 값을 증가시킨다.


  printf함수를 실행하고 나면, *ptr++ 앞의 *이 사라지고, ptr++만 남게 되는데,


  이는 주소값을 증가하라는 의미임으로, ptr의 주소값은 그 다음주소로 이동하게 된다.


  그렇기 때문에 그 다음 printf로 ptr의 값을 찍게 되면, ptr[1]의 값인 10이 찍히게 된다.




printf("%d", *ptr+1);        printf("%d", *ptr);


 : 포인터명 앞에 별표(*)를 찍음으로써, 값을 의미하며 *ptr 의 값은 10이 나오게 된다.


  값에다가 +1을 한 값을 출력하라고 하였기 때문에, *ptr+1은 11이 찍히게 된다.


  그러나, +1은 값자체를 증가시키는 것이 아니라, printf함수를 이용한 출력시에만 이용되는 것이기 때문에,


  *ptr을 다시 출력하게 되면, 원래의 값 10이 나오게 된다.




printf("%d", ++*ptr);        printf("%d", *ptr);


 : 포인터명 앞에 붙은 ++은 증감연산자 중에서 선 증감연산자로,


  해당 값을 먼저 증가 시킨 후, printf함수를 실행하기 때문에, 11이 찍히게 된다.


  증감연산자는 앞의 +1과 달리 ptr의 값 자체를 증가시키기 때문에,


  다음  printf함수로 출력하게 되면, 바뀐 값(11)이 찍히는 것을 알 수 있다.




printf("%d", *(ptr+1));        printf("%d", *ptr);


 : 포인터명에 +1이 붙었으니, 해당값을 증가시켜야 하나, 별표(*)와 괄호로 구분되어 있으므로,


  주소값을 증가시켜 값을 출력하라는 의미이기 때문에, 22가 찍히게 된다.


  +1은 앞에서도 말했다 싶이, 값자체를 증가하는 것이 아니기 때문에, 


  *ptr을 다시 출력하면, 원래의 값 11이 찍히게 된다.




printf("%d", *ptr+=1);        printf("%d", *ptr);


 : *ptr+=1은 *ptr= *ptr+1과 같기 때문에, 값을 증가시키라는 의미이다.


  그래서 11에 +1이 증가된, 12가 찍히게 된다.


  +=은 값 자체가 증가된 것이기 때문에, *ptr를 찍게 되면, 증가된 값인 12가 찍히게 된다.




printf("%d", *++ptr);        printf("%d", *ptr);


 : ++은 포인터명 앞에 붙었으니, 증감연산자 중에서 선 증감연산자인데, 


  별표(*)와 포인터명 사이에 쓰였으므로, *(++ptr)과 동일하다.


  그러므로, ptr의 주소값을 증가시킨 후에, 값을 출력하라는 의미로, 


  주소값이 증가된 22가 찍히게 된다.


  ++은 해당 값 자체를 증가 시키기 때문에, 다시 ptr을 찍게 되면 22가 찍히게 된다.




printf("%d", (*ptr)++);        printf("%d", *ptr);


 : 괄호의 값을 먼저 계산해야 함으로, 후증감연산자는 값을 증가시킨라는 의미이다.


  그렇기 때문에, 처음에 printf함수로 출력시, 22가 찍히게 되지만,


  2번째로 찍게 되면, 22에서 값이 1증가된 23이 찍히게 된다.

'C' 카테고리의 다른 글

배열  (0) 2018.01.08
입력버퍼 비우기  (0) 2018.01.06

배열이란 동일한 DataType을 담는 변수들의 집합이다.


개발자가 프로그램내에서 변수를 선언하게 되면, 


운영체제는 변수의 크기에 맞춰 메모리상의 빈 공간을 찾아 메모리를 할당한다.


변수들에게 할당된 공간은 운영체제가 임의로 찾은 공간이기에, 


프로그램내에 선언된 변수들은 메모리상에 그 위치가 붙어있을 수도 있고, 혹은 떨어져 있을 수도 있다.


그렇기 때문에 값을 넣거나 변경하기 위해서는 변수들을 일일이 처리할 수 밖에 없다.


<예시>



그러나 배열을 사용하게 되면, 굳이 일일이 처리할 필요가 없다.


개발자가 배열을 선언하게 되는 순간, 개발자가 설정한 배열의 크기만큼 메모리 공간에 잡히게 되는데, 


이는 위의 방식처럼 변수의 할당위치가 재각각이 아닌, 연속적으로 이어져 있다.



개발자는 p배열의 첫주소값을 이용하여, p배열이 가진 모든 요소들을 접근할 수 있기 때문에, 


반복문을 이용하여 일괄처리가 가능해 지는 것이다.


<예시>





[ 배열 ] 


기본형식 : DataType 배열명 [갯수];


배열 선언시에는 첨자사이의 숫자가 개발자가 만들고자 하는 배열의 갯수를 나타내지만,


선언 후에는 배열명은 배열의 시작주소를 나타내며, 첨자 사이의 숫자는 배열의 시작주소로부터 상대적인 거리를 나타낸다.


<예시>


p[0]는 배열의 시작주소로부터 한칸도 떨어져 있지 않다는 것을 의미한다.


p[1]은 배열의 시작주소로부터 한 요소의 크기만큼 떨어져있다는 것을 의미하는데, 


p배열은 int형 배열이기 때문에 시작주소로부터 4byte 떨어져 있다는 것을 알 수 있다.




일차원 배열에다가 +1을 하면, 한요소의 크기 만큼 떨어져 있다는 것을 의미하나,


2차원배열에 +1을 하게 되면, 한 행의 크기만큼 떨어져 있다는 것을 의미한다.


마지막으로, 3차원배열에 +1을 하게 되면, 한 면의  크기만큼 떨어져 있다는 것을 말한다.




[주소값과 값의 구분]


주소값과 값의 구분 기준은 첨자([ ])와 별표(*)이다.


위에서는 나타내지 않았지만, 배열의 첨자는 별표로, 별표를 첨자로도 바꾸어 나타낼 수 있다.


그렇기 때문에, 배열의 선언할 때의 첨자의 갯수혹은 별표의 갯수보다 더 적다면 주소값이고, 갯수가 동일하다면 값이다.


+배열의 첨자의 갯수혹은 별표의 갯수가 동일하더라도, 앞에 &가 붙어있다면 값이 아닌 주소값을 의미한다.



<예시>


int a[2][2][2];




#주소값


&a[0][0][0]   &a[0][0][1]  &a[0][1][0]  &a[0][1][1]  &a[1][0][0]  &a[1][0][1]  &a[1][1][0]  &a[1][1][1]


a[0][0]  a[0][0]+1  a[0][1]  a[0][1]+1  a[1][0]  a[1][0]+1  a[1][1]  a[1][1]+1


*a[0]  *a[0]+1  *(a[0]+1)  *(a[0]+1)+1  *a[1]  *a[1]+1  *(a[1]+1)  *(a[1]+1)+1


**a  **a+1  *(*a+1)  *(*a+1)+1  **(a+1)  **(a+1)+1  *(*(a+1)+1)  *(*(a+1)+1)+1


a[0]  a[0]+1  a[1]  a[1]+1


*a  *a+1  *(a+1)  *(a+1)+1


a  a+1




#값


a[0][0][0]   a[0][0][1]  a[0][1][0]  a[0][1][1]  a[1][0][0]  a[1][0][1]  a[1][1][0]  a[1][1][1]


*a[0][0]  *(a[0][0]+1)  *a[0][1]  *(a[0][1]+1)  *a[1][0]  *(a[1][0]+1)  *a[1][1]  *(a[1][1]+1)


**a[0]  *(*a[0]+1)  **(a[0]+1)  *(*(a[0]+1)+1)  **a[1]  *(*a[1]+1)  **(a[1]+1)  *(*(a[1]+1)+1)


***a  *(**a+1)  **(*a+1)  *(*(*a+1)+1)  ***(a+1)  *(**(a+1)+1)  **(*(a+1)+1)  *(*(*(a+1)+1)+1)


'C' 카테고리의 다른 글

포인터  (0) 2018.01.08
입력버퍼 비우기  (0) 2018.01.06

[Visual Studio 2015버전]


숫자를 입력한 뒤 Enter키를 누르게 되면, 다음에 입력받는 단계를 건너뛰는 경우가 발생한다.


<Example>


 #include"stdio.h"

 #pragma warning(disable : 4996)


 void main(){


 int num1, num2;

 char op;

 

 printf("Enter the 1st number : ");

 scanf("%d", &num1);


 printf("Enter the operation : ");

 scanf("%c", &op);


 printf("Enter the 2nd number : ");

 scanf("%d", &num2);


 printf("%d%c%d = %d", num1, op, num2, num1+num2);


}


  예제를 실행하게 되면, enter the 1st number : 에 커서가 깜빡거린다.


 그 곳에다가 3을 입력하고 Enter키를 누르게 되면,  다음과 같은 결과가 나오게 된다.



즉, 연산자를 입력할 공간이 사라지고, 다음 숫자를 넣을 공간에 커서가 깜빡거리게 된다.






[원인]


"이렇게 되는 이유는 Enter키 때문이다."


원리를 설명하자면,


scanf함수를 이용하여 값을 입력하게 되면, 변수에 값이 저장되기 전에 입력버퍼에 먼저 그 값이 쓰여지게 된다.



여기서 \0는 'Null'값을 말하며, 이는 Enter를 칠 경우 입력버퍼에 \0의 형태로 들어가게 된다.


이렇게 쓰여진 값들은 데이터타입에 따라 변수에 저장되게 된다.


num1에 저장되는 것은 오직 3뿐이다. 이유는 num1의 데이터 타입이 int 이기 때문이다.


'\0'는 char 타입이기 때문에, num1에는 저장될 수 없다. 그렇기 때문에 '\0'는 입력버퍼에 그대로 잔류하게 된다.


다음에 입력 받는 연산자가 char타입이기 때문에, 이 변수 op는 추가적인 입력없이 입력버퍼에 남아있는 '\0'를 저장하게 된다.



그렇기 때문에, 프로그램을 실행시켰을 때는 위와 같이, 연산자를 입력할 공간이 건너 뛰어, 다음숫자를 입력할 단계로 넘어가는 것처럼 보이게 된다.







[해결 방안]


1. getchar()이용


  getchar함수는 입력버퍼에서 문자 하나를 가져오는 함수이다.


  getchar()를 이용하게 되면, 입력버퍼에 '\0'를 가져오게 됨으로써, 입력버퍼가 비게 되어 다음 값을 입력받을 수 있다.


  <사용 예시>



 + 응용버전.


 getchar()는 문자하나만을 가져오기 때문에, 입력버퍼에서 있는 문자전체를 가져와서 입력버퍼를 비우고 싶을 경우에는


 위의 getchar()가 적혀있는 부분에, getchar() 대신, while(getchar()!='\n') 를 적어주면 된다. 


 while 문의 조건을 통해, 문자가 '\n'(개행문자)가 아닌 경우에는 모두 가져와서 입력버퍼를 비워주는 역활을 한다.





2. %*c 이용



 scanf함수에서 '%*c' 는 'read the data but do not assign it to a variable in the argument list' 이다.


 즉, 입력버퍼의 값을 읽어오지만, 그 값을 변수에 대입하지는 않는 다는 뜻이다.



<사용예시>


  #include"stdio.h"

  #pragma warning(disable : 4996)


  void main(){


  int num1, num2;

  char op;

 

  printf("Enter the 1st number : ");

  scanf("%d", &num1);


  printf("Enter the operation : ");


  scanf("%c", &op);     -> scanf("%*c%c", &op); 로 변환 : 입력버퍼에 있는 '\0'를 %*c에서 가져가게 된다. 


    그러나, %*c는 가져간 값을 변수에 대입하지는 않기 때문에, 다음 %c로 넘어가게 된다.


    (원래 입력버퍼에 있던 값을 한번, scanf로 입력하는 값 한번) = 두개의 문자를 입력받는 방식.


  printf("Enter the 2nd number : ");

  scanf("%d", &num2);


  printf("%d%c%d = %d", num1, op, num2, num1+num2);


 }





3. scanf("%c", &op) 한번 더 이용



<사용예시>



scanf("%c", &op)를 처음 사용하게 되면 op에는 '\0'의 값이 들어오게 된다.


두번째 이용 시에는, 입력버퍼에 남은 값이 없기 때문에 op변수에 키보드를 통해 값을 입력할 수 있게 된다.





4.  rewind(stdin) 이용


[ 기본형태 :  void rewind ( FILE * stream ) ]


rewind함수는 스트림의 위치를 재설정하는 함수이다.


스트림은 프로그램과 장치사이를 연결해 주는 통로라고 할 수 있으며, 


표준 스트림은 모든 프로그램에서 기본적으로 사용하는 3개의 스트림(stdin, stdout- 표준 출력, stderr - 표준 오류)을 말한다.


그 중에서도 stdin(standard input)은 표준 입력 스트림으로써, 


키보드에서 입력받는 값이 변수에 저장되기 전에 임시로 저장되는 공간으로 가는 통로라고 할 수 있으며, 


사용자의 개별적인 지정없이는 키보드에서 받아 오게 된다. 


또한 이 통로를 통해 값이 임시로 저장되는 공간을 입력버퍼라고 한다.



rewind함수는 스트림의 위치를 스트림의 시작점으로 이동하게 하는 함수로서, 


주는 곳에 stdin를 주게 되면, 입력 스트림의 위치를 처음 위치로 이동시키게 된다. 


rewind함수를 이용 후, 값을 입력하게 되면, 이전에 쓰여있던 값을 덮어 쓰고, 입력하게 된다. 



<사용예시>



+추가


비슷한 예시로는 fseek함수가 있다.


[ 기본형식 : int fseek(FILE *stream, long offset, int whence) ]


fseek함수는 rewind함수와 유사하게 위치를 재설정해주나,


시작점으로 이동하는 rewind함수와 다르게 위치를 이동시키는 함수로서, 인자를 3개를 요구한다.


offset는 기준점에서 부터 byte 단위로 사용자가 위치를 지정할 수 있으며, 


whence는 그 위치를 변경할 기준점으로 SEEK_SET, SEEK_CUR, SEEK_END 3가지가 있다.


SEEK_SET는 스트림의 시작점을, SEEK_CUR은 현재 스트림의 위치를, SEEK_END는 스트림의 마지막점을 말한다. 


<사용예시>

fseek(stdin, 0, SEEK_SET)을 이용하여 현재 스트림의 위치를 시작점으로 이동시켜 입력을 받을 수도 있지만,


fseek(stdin, -1, SEEK_CUR)를 통해, 현재스트림의 위치에서 -1한 위치로 이동시켜, 입력을 받을 수도 있다.



<사용예시>

참고자료 : https://www.joinc.co.kr/w/man/3/fseek





5. 공백(White Space) 이용


scanf함수의 기본적인 사용형식은 scanf("문자 서식 및 구분자", 데이터의 값) 이다. 


구분자란 문자를 여러개 입력 받는 경우 값을 구분해 주는 요소이다.


구분자는 공백(white space)혹은 개행문자(\n), Tab(\t) 등 여러가지가 있는데, 


이 구분자가 들어가게 되면 값 입력시 구분자형식과 동일한 값이 들어오게 되면


해당값을 입력에서 제외하고 입력을 받는다. 


+ 지정 구분자와 다른 형식의 구분자을 입력할 시에는 입력 값을 구분자로 인식하지 않고,


   값으로 인식하여 입력을 받아들인다.



<사용예시>



++예외적으로 안되는 함수


1. fflush함수


fflush함수는 원래는 출력버퍼를 비우는 함수로 이용되나, fflush(stdin)로 입력버퍼를 비우는 함수로도 이용할 수 있었다.


그러나, visual studio 2015년도 버전부터 보완을 강화시켜 이용이 불가능하다.


'C' 카테고리의 다른 글

포인터  (0) 2018.01.08
배열  (0) 2018.01.08

+ Recent posts