728x90

하나의 문자를 출력하는 함수


int putchar(int c);

int fputc(int c, FILE * stream);

 // *stdout은 모니터 출력, putchar함수와 동일한 결과


하나의 문자를 입력받는 함수


int getchar(void);

int fgetc(FILE * stream);  

// *stdin은 키보드로 문자 입력받음


파일의 끝에 도달하거나 함수호출 실패 시 EOF(End Of File) 반환

EOF는 파일의 끝을 알리기 위한 상수 -1 로 정의된다.



/*

  문자열 관련 입출력 함수

*/


#include <stdio.h>


int main()

{

  int ch1 = getchar();  // 문자 입력

  int ch2 = fgetc(stdin);  // 엔터 키 입력


  putchar(ch1);    // 문자 출력

  fputc(ch2, stdout);  // 엔터키 출력

  

  return 0;

}


/* ouput : 

p

p

두 번째 문자가 엔터 키이므로 하나의 문자가 입력되고 출력된것처럼 착각할 수 있음

(아스키 코드값이 10인 "\n")

*/



/*

  문자열 입출력에서의 EOF

  함수 호출 실패 또는 윈도에서 CTRL+Z 가 입력되는 경우(linux : Ctrl+D)

*/


#include <stdio.h>


int main()

{

  int ch;


  while (1)

  {

    ch = getchar();

    if (ch == EOF)

      break;

    putchar(ch);

  }


  return 0;

}



int getchar(void);

int fgetc(FILE * stream);


1바이트 크기 문자를 반환하는데, 반환형이 int인 이유

: char를 unsigned char로 처리하는 컴파일러도 존재


하지만 EOF는 -1로 정의된 상수

변환의 과정에서 양수로 형 변현될 수 있으므로

int형 변수는 기본적으로 signed int이므로 -1 반환에 문제없음



int getchar(void);

int fgetc(FILE * stream);


1바이트 크기 문자를 반환하는데, 반환형이 int인 이유?

: char를 unsigned char로 처리하는 컴파일러도 존재

하지만 EOF는 -1로 정의된 상수인데 

변환의 과정에서 양수로 형 변현될 수 있다.


int형 변수는 기본적으로 signed int이므로 -1 반환에 문제없음



/*

getchar,putchar 함수 이용


소-대문자 변환 출력 (알파벳 이외의 문자는 오류메시지 출력)

*/


#include <stdio.h>


int ConvCase(int ch);


int main()

{

  int ch;


  printf("대<-소문자 변환 : ");

  ch = getchar();

  ch = ConvCase(ch);


  if (ch == -1)  // 예외처리 (문자 아닐때)

  {

    puts("오류");

    return -1;

  }

  putchar(ch);

  puts("");

  

  return 0;

}


int ConvCase(int ch)

{

  int ASCII_Diff = 'a' - 'A';  

  // 아스키 코드에서 모든 영문 대소문자 차가 32로 같음 /  97-65  a-A,  98-66  b-B


  if (ch >= 'A' && ch <= 'Z')

    return ch + ASCII_Diff;

  if (ch >= 'a' && ch <= 'z')

    return ch - ASCII_Diff;

  else

    return -1;

}



/*

문자열 출력함수 puts, fputs


int puts(const char * s);   개행이 포함됨 ("\n")


int fputs(const char * s, FILE * stream);  

두번째 인자 stdout쓸 때 차이는 fputs에는 개행 ("\n")이 포함되지 않음

*/


#include <stdio.h>


int main()

{  

  char * str = "simple string";


  printf("1. puts test \n");

  puts(str);

  puts("So Simple String");


  printf("2. fputs test \n");

  fputs(str, stdout); 

  printf("\n");  //  fputs에는 개행이 포함되지 않음


  printf("3. END \n");


  return 0;

}



/*

  gets, fgets

  char * gets(char * s);

  char * fgets(char * s, int n, FILE * stream);  

  

  // int n은 총 문자열의 길이 / sizeof(str)

  NULL문자를 저장할 공간도 필요

*/


#include <stdio.h>


int main()

{  

  char str[7];  // 6 + NULL


  int i;

  for (i = 0; i < 3; i++)

  {

    fgets(str, sizeof(str), stdin);  // stdin 문자열 입력

    printf("Read %d: %s \n", i + 1, str);

  }


  return 0;

}


// fgets함수는 \n을 만날때까지 문자열을 읽어들이며,

 \n을 버리지않고 문자열의 일부에 포함시킨다.


중간에 삽입된 공백문자도 문자열의 일부로 받아들인다.



출력버퍼를 비우는 fflush 함수

int fflush(FILE * stream);


fflush(stdout);


출력 버퍼를 비운다는 것은 저장된 데이터를 지우는 것이 아님.

출력버퍼에 저장된 데이터를 목적지로 최종전송하는 것.


입력버퍼를 비운다는 것은 삭제의 의미에 가까움.


fflush(stdin); // 컴파일러에 따라 허용되는 경우도 있으나 사용하지 않는 것이 좋다.


입력버퍼를 비우는 함수가 따로 존재하지 않는 것은

read하면 비워지기 때문


이를 이용해 아래와 같은 함수를 정의할 수 있다.



void ClearLineFromReadBuffer(void)

{

while(getchar()!='\n');    // 개행문자를 만날때까지 읽어들임, 읽어들인 문자는 따로 저장하지않고 비워지게 된다.

}



/*

입력버퍼를 비우는 예제

*/

#include<stdio.h>


void ClearLineFrom_ReadBuffer(void);


int main(void)

{

char perID[7];

char name[10];


fputs("주민번호 앞 6자리 입력 : ", stdout);

fgets(perID, sizeof(perID), stdin);

ClearLineFrom_ReadBuffer();


fputs("이름 입력 : ", stdout);

fgets(name, sizeof(name), stdin);

printf("주민번호 : %s \n", perID);

printf("이름 : %s \n", name);


return 0;

}


void ClearLineFrom_ReadBuffer(void)

{

while (getchar() != '\n');

}




/*
문자열 길이를 반환하는 함수 strlen
strlen을 활용하고 문자열의 마지막에 삽입되는 null을 없앤 길이 출력
*/
#include<stdio.h>

void RemoveNULL(char str[]);

int main(void)
{
char str[100];
printf("문자열 입력 : ");
fgets(str, sizeof(str), stdin);
printf("길이 : %d, 내용: %s \n", strlen(str), str);

RemoveNULL(str);
printf("RemoveNULL : %d, 내용: %s \n", strlen(str), str);

return 0;
}

void RemoveNULL(char str[])
{
int lengh = strlen(str);
str[lengh - 1] = 0;
}



문자열을 복사하는 함수 strcpy (string copy)

char * strcpy(char * dest, const char * src);


src에서 dest로 복사 (복사된 문자열의 주소 값 반환)


char * strncpy(char * dest, const char * src, size_t n);

복사되는 문자열의 길이를 n으로 제한


메모리 공간의 효율적인 사용과 프로그램 안정성을 위해 strncpy를 더 많이 쓴다.




/*

문자열을 복사하는 함수 strcpy (string copy)

strncpy (복사되는 문자열의 길이를 n으로 제한)

char * strncpy(char * dest, const char * src, size_t n);

*/

#include<stdio.h>


int main(void)

{

char str1[20] = "1234567890";

char str2[20];

char str3[5];

// str1의 문자열이 str1에 복사됨

strncpy(str2, str1);

puts(str2);


// str1의 문자열이 str3에 복사됨(str3의 길이만큼 제한)

strncpy(str3, str1, sizeof(str3));

puts(str3);


strncpy(str3, str1, sizeof(str3) - 1); // null문자 넣어줄 공간을 빼고 복사

str3[sizeof(str3) - 1] = 0; // null문자를 넣어줌

puts(str3);


return 0;

}



/*

문자열을 덧붙이는 함수 strcat  (STRing conCATenation)

strncat (복사되는 문자열의 길이를 n으로 제한)

char * strncat(char * dest, const char * src, size_t n);

*/

#include<stdio.h>


int main(void)

{

char str1[20] = "First~";

char str2[20] = "Second";


char str3[20] = "Simple num: ";

char str4[20] = "1234567890";


//str2를 str1 뒤에 덧붙임

strcat(str1, str2);

puts(str1);


//n만큼 덧붙이되 null문자 맨뒤에 붙여짐

strncat(str3, str4, 7); // 1~7까지 붙여지고 끝에 NULL이 포함

puts(str3);


return 0;

}




문자열 비교함수 strcmp (string compare)

int strcmp(const char * s1, const char * s2);
int strncmp(const char * s1, const char * s2, size_t n);

두 문자열의 내용이 같으면 0, 같지않으면 0이 아닌값 반환

s1이 더 크면 0보다 큰 값 반환, s2가 더 크면 0보다 작은 값 반환

크고 작음은 아스키 코드값을 근거로 함 
(아스키코드 값이 더 크면 더 큰 문자열로 인식)

문자열에선 가장 앞의 문자를 가지고 비교
(문자열의 끝에는 null이 포함)

/*
문자열 비교함수 strcmp (string compare)

int strcmp(const char * s1, const char * s2);
int strncmp(const char * s1, const char * s2, size_t n);
*/

#include<stdio.h>

int main(void)
{
char str1[20];
char str2[20];
printf("문자열 입력 1: ");
scanf("%s", str1);
printf("문자열 입력 2: ");
scanf("%s", str2);

if (!strcmp(str1, str2)) // 0이 아닌 값은 true, 같을 때 0(false) 반환 == if(strcmp(str1, str2)==0
{
puts("두 문자열 일치");
}
else
{
puts("두 문자열 불일치");

if (!strncmp(str1, str2, 3)) // 3글자까지만 비교
puts("그러나 앞 세 글자는 동일");
}

return 0;
}


문자열의 내용을 변환해주는 함수들


int atoi(const char * str); // atoi : 문자열의 내용 -> int형 변환

long atol(const char * str); // atol : 문자열의 내용 -> long형 변환

double atof(const char * str); // atof : 문자열의 내용 -> double형 변환


/*

그 이외의 변환함수 atoi, atol, atof

*/


#include<stdio.h>


int main(void)

{

char str[20];


fputs("정수 입력: ", stdout);

fgets(str, sizeof(str), stdin);

int result = atoi(str);

printf("%d \n", result*result);


return 0;

}

'Study > C' 카테고리의 다른 글

파일 입출력 공부  (0) 2016.08.25
구조체 공부  (0) 2016.08.23
c 복습-문제풀이2  (0) 2016.08.22
섭씨->화씨 변환, 최대 공약수 구하기  (0) 2016.05.03
2016-04-07-업무일지_구조체 및 함수  (0) 2016.04.07
728x90


/*  Pointer Swap (double pointer 이용)  반드시 포인터에 저장된 값을 swap하도록! */

#include<stdio.h>


void SwapPtr(int* *dptr1, int* *dptr2)

{  

  int *temp = *dptr1;  // type이 일치해야 함

  *dptr1 = *dptr2;

  *dptr2 = temp;  

  //(*dptr1 = &num1 = ptr1 / *dptr2 = &num2 = ptr2) 

}


int main(void)

{

  int num1 = 10;

  int num2 = 20;


  int *ptr1;

  int *ptr2;


  ptr1 = &num1;

  ptr2 = &num2;

  printf("*ptr1, *ptr2 : %d  %d \n", *ptr1, *ptr2);


  SwapPtr(&ptr1, &ptr2);

  printf("*ptr1, *ptr2 : %d %d \n", *ptr1, *ptr2);

  return 0;

}



/*  Pointer Array Type 


// int ** dptr = &ptrArr[0]; / *(dptr[0]) = *(ptrArr[0]) = *(ptr1) = num1

// *ptr1=&num1;

*/

#include<stdio.h>


int main(void)

{

  int num1 = 10;

  int num2 = 20;

  int num3 = 30;


  int *ptr1 = &num1;

  int *ptr2 = &num2;

  int *ptr3 = &num3;

  

  int *ptrArr[] = { ptr1, ptr2, ptr3 }; 

  int ** dptr = ptrArr; // ptrArr이 double pointer,  ptrArr의 주소값에 대입하는 것

    

  printf("%d %d %d \n", *(ptrArr[0]), *(ptrArr[1]), *(ptrArr[2]));

  printf("%d %d %d \n", *(dptr[0]), *(dptr[1]), *(dptr[2]));


  return 0;

}



ptrArr은 int형 포인터를 요소로 갖는 배열의 이름이기 때문에 더블 포인터형


따라서 

 int **dptr = ptrArr;





/*  

  int * maxPtr;  int * minPtr;  int arr[5];

  함수 MaxAndMin, 위 배열과 두 포인터 변수에 대한 정보 전달

  maxPtr에 가장 큰값이 저장된 배열요소 주소 값, minPtr에 가장 작은 값이 저장된 배열요소 주소값 저장

*/


#include <stdio.h>


void MaxAndMin(int *arr, int size, int **MaxPtr, int **MinPtr);


int main()

{  

  int * maxPtr;

  int * minPtr;

  int arr[5];


  int i;

  for (i = 0; i < 5; i++)

  {

    printf("%d번째 정수 입력 : ", i + 1);

    scanf("%d", &arr[i]);

  }  


  MaxAndMin(arr, sizeof(arr) / sizeof(int), &maxPtr, &minPtr);

  printf("최대 : %d, 최소 : %d \n", *maxPtr, *minPtr);


  return 0;

}


void MaxAndMin(int *arr, int size, int **MaxPtr, int **MinPtr)

{

  int *max;

  int *min;  

  max = min = &arr[0];


  int i;

  for(i=0; i<size; i++)

  {

    if (*max < arr[i])

      max = &arr[i];


    if (*min > arr[i])

      min = &arr[i];    

  }


  *MaxPtr = max;

  *MinPtr = min;

}


/*  

  2d Array Address

*/


#include <stdio.h>


int main()

{

  int arr2d[3][3];

  printf("%p \n", arr2d);

  printf("%p \n", arr2d[0]);

  printf("%p \n \n", &arr2d[0][0]);


  printf("%p \n", arr2d[1]);  // +12  sizeof(int) x 3

  printf("%p \n", &arr2d[1][0]);  // +12


  printf("sizeof(arr2d): %d \n", sizeof(arr2d));  // 배열 이름의 size는 배열 전체의 크기

  printf("sizeof(arr2d[0]): %d \n", sizeof(arr2d[0]));  // 각 행의 size반환 (12)

  printf("sizeof(arr2d[1]): %d \n", sizeof(arr2d[1]));

  printf("sizeof(arr2d[2]): %d \n", sizeof(arr2d[2]));


  return 0;

}


2차원 배열이름의 포인터 형은 가리키는 대상과 가로 길이에 의존적이다. int [4][2]  [6][2]


int arr[3][4]의 포인터 형은

int (*ptr) [4];  //  [4]는 가로길이

포인터 연산시 4칸씩 건너뛰는 int형 변수 포인터


포인터 연산(+,-)을 했을 때의 주소값을 생각하면 된다.



/*  

  2차원 배열의 포인터 형

*/


#include <stdio.h>


int main()

{

  int arr1[2][2] = {

    {1,2},{3,4}

  };


  int arr2[4][2] = {

    {1,2,},{3,4},{5,6},{7,8}

  };


  int(*ptr)[2];

  int i;


  ptr = arr1;  // arr은 상수, ptr은 변수이므로 ptr이 arr1도 arr2도 가리킬 수 있다.

  printf("** Show 2,2 arr1 **\n");

  for (i = 0; i < 2; i++)

    printf("%d %d \n", ptr[i][0], ptr[i][1]);


  ptr = arr2;

  printf("** Show 2,2 arr1 **\n");

  for (i = 0; i < 4; i++)

    printf("%d %d \n", ptr[i][0], ptr[i][1]);


  return 0;

}


int* whoA [4];  // 포인터 배열 : 포인터 변수로 이루어진 배열

int (*whoB) [4];  // 배열 포인터 : 배열을 가리킬 수 있는 포인터 변수



함수포인터 


(매개변수)(반환형)


무엇을 전달받고 

무엇을 반환하는지 이해


/*  Function Pointer

num1,num2값을 더해서 보여주는 함수

string을 보여주는 함수를 메인함수에서 함수 포인터 변수로 호출

*/

#include<stdio.h>


void ShowAdd(int n1, int n2);

void ShowString(char * str);


int main(void)

{

  int num1 = 10, num2 = 20;

  char * str = "String";


  void(*Add_FuncPointer)(int, int) = ShowAdd;  // (int n1, int n2)

  void(*String_FuncPointer)(char *) = ShowString;


  Add_FuncPointer(num1,num2);

  String_FuncPointer(str);

  

  return 0;

}


void ShowAdd(int n1, int n2)

{

  printf("%d + %d = %d \n", n1, n2, n1 + n2);

}


void ShowString(char * str)

{

  printf("%s \n", str);

}



/*  Useful Function Pointer

*/

#include<stdio.h>


int WhoIsFirst(int age1, int age2, int(cmp)(int n1, int n2));

int OlderFirst(int age1, int age2);

int YoungerFirst(int age1, int age2);


int main(void)

{

  int age1 = 20;

  int age2 = 30;

  int first;


  printf("늙은 사람이 먼저 입장 \n");

  first = WhoIsFirst(age1, age2, OlderFirst);

  printf("%d세와 %d세중 %d세가 먼저 입장 \n\n", age1,age2,first);


  printf("젊은 사람이 먼저 입장 \n");

  first = WhoIsFirst(age1, age2, YoungerFirst);

  printf("%d세와 %d세중 %d세가 먼저 입장\n\n", age1,age2,first);


  return 0;

}


int WhoIsFirst(int age1, int age2, int(cmp)(int n1, int n2))

{

  return cmp(age1, age2);

}


int OlderFirst(int age1, int age2)

{

  if (age1 > age2)

    return age1;

  else if (age1 < age2)

    return age2;

  else

    return 0;

}


int YoungerFirst(int age1, int age2)

{

  if (age1 < age2)

    return age1;

  else if (age1 < age2)

    return age2;

  else

    return 0;

}



/*  

  18-1

*/


#include <stdio.h>


int main()

{

  int * arr1[5];

  int * arr2[3][5];


  int **ptr = arr1;

  int (*ptr2)[5] = arr2;  


  return 0;

}



arr[1][0][1]

== ( (*arr)+1) [0][1]

== (* (* (arr+1) +0 ) )[1]

== *( * ( * ( arr+1) + 0 ) +1 ) )

== ( * ( arr[1]+0 ) )[1]

==  *(*(arr[1]+0)+1) 

==  *(arr[1][0]+1)



/*  

   argument count, argument vector

*/


#include <stdio.h>


int main(int argument_count, char *argument_vector[])

{

  int i = 0;

  printf("전달된 문자열 수 : %d \n", argument_count);


  for (i = 0; i < argument_count; i++)

    printf("%d번째 문자열: %s \n", i + 1, argument_vector[i]);

      

  return 0;

}


/*

output:

전달된 문자열 수 : 4

1번째 문자열: E:\Visual Studio 2015\Projects\C_Study\Debug\C_Study.exe

2번째 문자열: I

3번째 문자열: Hate

4번째 문자열: You!

*/




/*  

   Argument Vector Parameter Type

*/


#include <stdio.h>


void Show_All_String(int argc, char *argv[]);


int main()

{

  char *str[3] = {

    "수박수박쑤",

    "씨발라먹을",

    "씨프로그래밍"

  };

  Show_All_String(4, str);

        

  return 0;

}


void Show_All_String(int argc, char *argv[])

{

  int i;

  for (i = 0; i < argc; i++)

    printf("%s \n", argv[i]);

}



/*

  end of argument vector (null)

*/


#include <stdio.h>


int main(int argument_count, char *argument_vector[])

{

  int i = 0;

  printf("전달된 문자열 수 : %d \n", argument_count);


  while (argument_vector[i] != NULL)

  {

    printf("%d번째 문자열: %s \n", i + 1, argument_vector[i]);

    i++;

  }

  return 0;

}



728x90
/* 섭씨 온도 입력하면 화씨 온도 반환 CelToFah 함수
그 반대 FahToCel 함수 정의및 호출
Fah=1.8 x Cel+32 */

#include <stdio.h>

double CelToFah(double c)
{
	return 1.8*c + 32;
}

double FahToCel(double f)
{
	return (f - 32) / 1.8;
}

int main()
{
	int select;
	double num;

	printf("1. 섭씨℃->화씨℉	2. 화씨℉->섭씨℃-\n");
		printf("선택:");
		scanf("%d", &select);

	if (select == 1)
	{
		printf("섭씨℃ 입력: ");
			scanf("%lf", &num);
		printf("섭씨℃->화씨℉: %f \n", CelToFah(num));
	}
	else if (select == 2)
	{
		printf("화씨℉ 입력:");
			scanf("%lf", &num);
		printf("화씨℉->섭씨℃: %f \n", FahToCel(num));
	}

	return 0;
}


Output:







/* 인자로 전달된 수만큼의 피보나치 수열을 출력하는 함수
5를 입력하면 5! */

#include <stdio.h>

void Fibo(int num)
{
	int f1 = 0;
	int f2 = 1;
	int f3;
	int i;

	if (num == 1)
		printf("%d ", f1);
	else
		printf("%d %d ", f1, f2);

	for (i = 0;  i<num-2;  i++) // 0과 1일 경우는 위의 if~else문에서 출력
	{
		f3 = f1 + f2;
		printf("%d ", f3);
		f1 = f2;
		f2 = f3;
	}
}

int main()
{
	int n;
	printf("출력하려는 피보나치 수열갯수 (1이상 입력) : ");
	scanf("%d", &n);

	if (n < 1)
	{
		printf("1 이상 값 입력하세요 \n");
		return -1;
	}
	Fibo(n);
	return 0;
}


Output:






최대 공약수(Greatest Common Measure) 구하기 (유클리드 호제법 이용)

알고리즘

  1. 두 수 n1,n2 입력
  2. n이 0이라면, n2 출력하고 알고리즘 종료.
  3. n이 n2를 나누어 떨어지면, n을 출력하고 알고리즘 종료.
  4. 그렇지 않으면, n2를 n1로 나눈 나머지를 새롭게 n2에 대입하고, n2와 n1을 바꾸고 3.으로 돌아온다.


예를 들어 6, 12의 GCM을 구할 때, 12가 6을 나누어 떨어지니 6을 출력하고 알고리즘을 종료한다.

#include<stdio.h>

int GCM(int n1, int n2);


int main(void)
{
	int n1;
        int n2;

	printf("두 개의 정수 입력: ");
	scanf("%d %d", &n1, &n2);

	printf("GCM : %d \n", GCM(n1, n2));
	return 0;
}

int GCM(int n1, int n2)
{
	int result;
	result = n1;
	while(n1%result !=0 || n2%result !=0)
		result--;
	return result;
}

이 문제에선 6, 9의 GCM을 구한다면,

int result;
	result = n1;
	while(n1%result !=0 || n2%result !=0)
		result--
n1=6, result=6

6과 6을 나눈 나머지는 0,     9와 6을 나눈 나머지는 3이므로 
=0 (false) || !=0 (true) 가 된다.

따라서 result--가 되고 while을 반복해나가다보면
6%3=0 || 9%3=0 이 되어 while문을 빠져나가고 result값인 3을 return하며 종료된다.



728x90

구조체와 배열


연관되었지만 타입이 다른 자료형의 경우는 구조체, 

같은 경우는 배열 사용



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>

struct person
{
    char name[20];
    char phoneNum[20];
    int age;
};

int main()
{
    struct person man1, man2;
    strcpy(man1.name, "안성준");
    strcpy(man1.phoneNum, "010'1122-3344");

    return 0;
}


위의 소스를 아래와 같이 비유할 수 있다.



 붕어빵 기계 틀

 struct person

 타입

 붕어빵

 man

 변수 (메모리를 차지)


  


atoi 함수 예제 소스 // a to i            ascii->int 문자열을 정수형으로 변환

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include <stdio.h> #include <stdlib.h> //atoi함수를 사용하기 위한 헤더 int main() { char str[20]; printf("정수 입력: "); scanf("%s", str); printf("%d \n", atoi(str)); printf("실수 입력: "); scanf("%s", str); printf("%g \n", atof(str)); return 0; }


실수 15.0을 입력하면 정수 15로 출력된다.




typedef을 쓰는 두가지 이유 


typedef unsigned int     size_t;   // 범용의 효과 : int나 short만 바꿔도 모든 size_t의 type이 바뀐다.

typedef unsigned short  size_t;



축약의 효과 

typedef unsigned in uInt;    // ulnt





#include <stdio.h>

int main()
{
    int iNum1=1;
    char str[5];
    int iNum2=2;

    printf("iNum1 : %d \n", iNum1); 
    printf("iNum2 : %d \n", iNum2);

    printf("iNum1 address : %x \n", &iNum1); 
    printf("str address : %x \n", &str);
    printf("iNum2 address : %x \n", &iNum2);

    scanf("%s", str);

    printf("[%s]\n", str); // 문자열 값 그대로 출력 문자열 %s에는 []를 씌우는 것이 좋다. 
    printf("iNum1 : %d \n", iNum1);  // 
    printf("iNum2 : %d \n", iNum2);

    return 0;
}



Output:

1
2
3
4
5
6
7
8
iNum1 : 1 
iNum2 : 2 
iNum1 address : ff9066b0 
str address : ff9066b7 
iNum2 address : ff9066ac 
[]
iNum1 : 1 
iNum2 : 2 


지역변수와 메모리 Stack


가장 최근의 지역변수가 재사용할 확률이 높다.

메모리의 stack에는 일반적으로 값이 밑에서부터 위로 만들어진다.



넣어진 종이컵을 꺼내려면 나중에 넣은 종이컵부터 꺼내게 되는 것과 같다.


  1. iNum2    //  address : ff9066ac 
  2. str          // ff9066b7
  3. iNum1    // ff9066b0





fgets 함수

scanf와 gets는 입력할 수 있는 문자에 제한이 없기에 오버플로우에 취약하다.



가급적이면 fgets를 쓰는 것이 좋다. (int size : 입력받는 값을 제한)


 char *fgets(char *s, int size, FILE *stream);



fgets 예제소스


#include <stdio.h>

void ClearLineFromReadBuffer(void)
{
    while(getchar()!='\n');
}

int main(void)
{
    char perID[7];
    char name[10];

    fputs("주민번호 앞 6자리 입력: ", stdout);
    fgets(perID, sizeof(perID), stdin);
    ClearLineFromReadBuffer();      // 입력버퍼 비우기

    fputs("이름 입력: ", stdout);
    fgets(name, sizeof(name), stdin);

    printf("주민번호: %s\n", perID);
    printf("이름: %s\n", name);
    return 0;
}
       



Output :





'Study > C' 카테고리의 다른 글

c 복습-문제풀이2  (0) 2016.08.22
섭씨->화씨 변환, 최대 공약수 구하기  (0) 2016.05.03
2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
728x90

배열


2차원에서 가로의 크기는 정해줘야 함






이중 포인터와 다중포인터



 PPP 

 PP

 P

  num A=100

 int***

  int**

 int*

  int


 



 대상의 type 

 자기자신의 type 

 int  

 (포인터)

     


 가리키는 대상

 포인터

 PP 

 *PPP

 

  **PPP

 B    

  ***PPP




 int * whoA[4]={&num1, &num2, &num3, &num4};  // 포인터 배열이고 16byte

 int (*whoB)[4]=arr2d;                                        // 배열 포인터이고 4byte


이중 포인터 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int main(void)
{
    double num = 3.14;
    double *ptr = &num;
    double **dptr = &ptr;
    double *ptr2;

    printf("%9p %9p \n", ptr, *dptr);
    printf("%9p %9p \n", num, **dptr);
    ptr2 = *dptr;
    *ptr2 = 10.99;
    printf("%9g %9g \n", num, **dptr);
 
    return 0;
}



Output:

1
2
3
0xffb30790 0xffb30790 
0x51eb851f 0x40091eb8 
    10.99     10.99 






포인터 변수에 const 선언 // const를 붙이면 해당 변수를 상수로 취급하게 된다.

#include <stdio.h>

int main()
{
    char *P1="TEST";
    const char *P2="TEST";
    char const *P3="TEST";
    char * const P4="TEST";
    const char * const P5="TEST";
    char const * const P6="TEST";

    printf("P1=[%s], [%p]\n", P1, P1);
    printf("P2=[%s], [%p]\n", P2, P2);
    printf("P3=[%s], [%p]\n", P3, P3);
    printf("P4=[%s], [%p]\n", P4, P4);
    printf("P5=[%s], [%p]\n", P5, P5);
    printf("P6=[%s], [%p]\n", P6, P6);

    printf(P1="zest\n");
    printf(P1="zest\n");
    printf(P1="zest\n");
   
    //printf(P4=zest);
    //printf(P5=zest);
    //printf(P6=zest);
    return 0;
}



리눅스에서는 주소가 모두 같게 나온다.

Output:

1
2
3
4
5
6
7
8
9
P1=[TEST], [0x8048698]
P2=[TEST], [0x8048698]
P3=[TEST], [0x8048698]
P4=[TEST], [0x8048698]
P5=[TEST], [0x8048698]
P6=[TEST], [0x8048698]
zest
zest
zest





메인 함수를 통한 인자 전달 // gcc 흉내내기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

#include <stdio.h> int main(int argc, char *argv[]) // argc = 지정해준 명령행 인자의 개수 저장, argv = 문자열 배열 포인터 { int i=0; if(1==argc) { printf("gcc: fatal error: no input files \n"); return 0; } printf("전달 문자열 수: %d \n", argc); for(i=0; i<argc; i++) printf("%d번째 문자열: %s \n", i+1, argv[i]); return 0; }


전달된 문자열이 하나이므로 조건에 맞는 아래 문장이 출력된다.


Output:

1
gcc: fatal error: no input files 






EOF (End Of File) // 파일의 끝


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main()
{
    int ch;

    while(1)
    {
        ch=getchar(); 
        if(ch==EOF)  
            break;
        putchar(ch); 
    }
        return 0;
}


getchar를 통해 입력버퍼의 문자를 읽어들임

enter가 입력될때까지 키보드 입력값들을 계속해서 버퍼에 저장. enter가 파일의 끝이 된다.






fprintf 함수 //  특정한 스트림에 일련의 데이터를 특정한 형식에 맞추어 쓰게 된다.   리눅스 man 3 fprintf 참조

1
2
3
4
5
6
7
#include <stdio.h>

int main()
{
    fprintf(stdout, "test \n");
    return 0;
}


stdout(표준출력)을 통해 test라는 글자가 출력.

printf 함수가 실제로 출력하는 것이 없고 fprintf에 지시해서 출력하는 것이라고 할 수 있다.


Output:

1
test 


'Study > C' 카테고리의 다른 글

섭씨->화씨 변환, 최대 공약수 구하기  (0) 2016.05.03
2016-04-07-업무일지_구조체 및 함수  (0) 2016.04.07
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
20160329_C기초, 디버깅  (0) 2016.03.29
728x90

배열의 이름은 포인터이다.

int형 배열의 주소값 차는 4바이트이며, 주소값의 변경은 불가능하다. (값을 바꿀 수 없는 상수형)


포인터 변수와 배열의 이름 모두, 메모리의 주소값을 나타내고 저장한다.


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
	int arr[3] = { 0, 1, 2 };
	printf("배열의 이름: %p \n", arr);
	printf("첫번째 요소: %p \n", &arr[0]);
	printf("두번째 요소: %p \n", &arr[1]);
	printf("세번째 요소: %p \n", &arr[2]);
	// arr = &arr[i];  // 이 문장은 컴파일 에러를 일으킨다.
	return 0;
}



Output:

1
2
3
4
배열의 이름: 0xff920370 
첫번째 요소: 0xff920370 
두번째 요소: 0xff920374 
세번째 요소: 0xff920378 


 


#include <stdio.h>

int main()
{
    char *cpStr="hello world \n";
    
  char caStr[20];
    printf("Hello world \n");
    printf(cpStr);

    caStr[0]='h';
    caStr[1]='e';
    caStr[2]='l';
    caStr[3]='l';
    caStr[4]='0';

    printf(caStr);
    putchar('\n');
    return 0;

}

castr의 배열에 저장된값 출력 배열의 경우 마지막에 null을 넣지 않으면 특수문자 \0 이 자동으로 붙음 그래서 castr[4]는 0을 넣음



임베디드

7F 45 4C // ELF파일임을 나타내는 아스키 코드







#include <stdio.h>

 int main(void) 
{
     char str1[] = "My String";
     char *str2 = "Your String";
     printf("%s %s \n", str1, str2);
     printf("str1 address : %p \n", str1);

     printf("main address", main);
     printf("str address", str2);

     printf("str2 address : %p \n", str2);
     str2 = "Our String";
     printf("%s %s \n", str1, str2);

     str1[0] = 'X';
     //str2[0] = 'X';
     printf("%s %s \n", str1, str2);
	    
     return 0;	
}




단순하게 화면을 출력할꺼면 포인터를 쓰는 것이 좋다.   // char *str2 = "";

위의 예제에서 포인터는 stack 영역에서 4byte를 차지하고 문자열은 10바이트를 차지한다. (M/y/_/S/t/r/i/n/g/null)



문자를 수정하려면 문자열을 쓴다.  // char str1[] = "";


메모리의 code영역은 Read only라 쓰면 안됨. (위의 소스에서 18행을 주석처리한 이유)

도스에서 허용하지만 리눅스에선 안되며 원래 쓰지 않는 것이 맞다.





포인터를 활용한 printf문

1
2
3
4
5
6
7
8
9
#include <stdio.h>

int main(void)
{
	char *cpStr = "A=%d \n";
	int A = 100;
	printf(cpStr, A);
	return 0;
}



Output:

1
A=100 



728x90

전역변수

 

어디서든 접근이 가능한 변수

전역변수와 지역변수의 이름을 달리하는 것이 좋다.

 



 

전역변수 아래와 같이 선언했을 때, 만들어진 파일의 용량이 엄청 커진다.

 

int A[1024*1024]={1, };

 

 


전역변수의 선언은 신중해야 한다.

프로그램이 복잡해지고 크기가 증가한다.

 

 

int A;

전역변수 A의 값은 0

 

 

 

 

지역변수에 static 선언하면?


: 전역변수의 성격을 지니게 됨


처음 1회만 초기화, 프로그램 종료시까지 메모리 상주(전역변수의 특성)

선언된 함수내에서만 접근 가능(지역변수의 특성)

 




전역변수에 static 선언하면?


분할 컴파일시, 파일간에 접근 불가능 (개별화됨)

 

 

 

// main.c 소스

#include <stdio.h>

int a;
int main(void)
{   
    printf("main: A = %d \n", a);
    test();
    printf("main: A = %d \n", a);
    return 0;
}

 

 

// test.c 소스

#include <stdio.h>

int a;
void test(void)
{
    printf("test : a = %d \n",a);
    a = 777;
    printf("test : a = %d \n",a);
    return;
}

 

 

 

test.c 소스 3행의 int a;에 static을 붙였을 때의 출력결과

 

 

 

 

 

 

비쥬얼 스튜디오 실습

 

 

위의 소스를 작성후 6행에 중단점 설정

 


주소를 고정하고 메모리의 값을 알기 위해 아래의 과정을 따라한다.


 

DYNAMIC BASE를 NO로 설정하면 주소가 고정된다.

 

디버그할 때 메모리의 내용보기

 

바로 위와 같이 설정하면 디버그시, 주소와 함께 메모리의 정보가 표시된다.


조사식에 &iNum을 넣으면 주소를 알 수 있고, 메모리란의 주소에 값을 넣으면 내용을 볼 수 있다. 

 

 

iNum의 주소 0x 00 19  fe  fc


메모리에 Little Endian 으로 fc  fe  19  00 이 올라가있음을 볼 수 있다.

 

 


포인터 변수의 크기

32bit system : 포인터 변수의 크기가 4byte

64bit system : 포인터 변수의 크기가 8byte




어셈블리 코드에서 dword ptr은 4byte pointer,

word ptr은 2byte pointer를 가리킨다.



 마찬가지로 포인터의 주소를 통해 값을 볼 수 있다. 



메모리의 TEXT 부분에 현재 실행중인 명령을 담고 있는 것이 Instruction Pointer이다.

EIP는 IP가 16비트에서 32비트 시스템으로 오면서 Extended 된것으로, 디버그시 EIP 레지스터도 확인 가능하다.





포인터 주소(0x 0019 FEF8)를 따라가서 메모리에 든 값 51EB 851F를 10진수로 바꿔보면, 

1,374,389,535라는 값이 나온다.


  

'Study > C' 카테고리의 다른 글

2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160329_C기초, 디버깅  (0) 2016.03.29
20160308_업무일지_그 밖의 기초 학습  (0) 2016.03.08
20160307_업무일지_파일 입출력  (0) 2016.03.07
728x90


프로그래밍 공부 과정

C → win32 API  →  C++  → MFC구조와 원리  →  MFC Application Programming

 

한빛

win32 API 정복

상 - 1~9챕터

 

 

오렌지미디어 열혈 C++

한빛 뇌를 자극하는 C++

 

한빛 Unix/Linux 필수 유틸리티

 

 

 

 

비쥬얼 스튜디오 실습

break 포인트를 지정해놓아야 디버그모드를 쓸 때 변수값이 어떻게 변하는지 알기 쉽다.

 

프로시져 단위 실행  (printf와 같은 함수 내부로 들어갈 수 있다)

전체한번에 수행 (f10)

 

ctrl+f5       디버그 하지않고 시작

shift+f5     디버그 모드 나가기

 

 

 

 

 

위와 같이 선택해서 프로젝트 파일 생성


옵션에서 줄 번호가 나오도록 수정 

 


디버그(프로그램상의 오류. 즉, 버그를 바로 잡는 것)를 할 때

f9 혹은 빨간 동그라미가 보이는 곳에 마우스 클릭을 해서 중단점을 설정할 수 있다. 


num값이 5가 되면 while문을 탈출하게 되는데, 중단점을 설정하게 되면 특정위치까지만 디버깅을 할 수 있게 된다.

  

 

아래 부분에 조사식에 num<5를 넣어 값과 참,거짓 여부를 알 수 있다. 



프로시저 단위실행을 했을 때, printf 함수내로 진입한 모습이다. 나가려면 프로시져 나가기를 누른다.


한단계식 코드 실행을 했을 때, 노란색 화살표로 진행지점과 도스창을 통한 출력여부를 확인가능하다. 


지역탭에서 위와 같이 각각의 값을 확인가능하다. result는 쓰레기값임을 알 수 있다. 


위의 소스에서도 조사식을 통해 값과 참, 거짓 여부를 디버깅하면서 볼 수 있다. 


 num1, num2가 더해지고 result 값에 5가 넣어진 걸 볼 수 있다.


printf 함수를 통해 도스창에도 위와 같이 사칙연산의 결과값이 나오고 값이 반환된다. (return 0;)

728x90

구구단 3단 소스 (http://codepad.org/ZT1RrUn5)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>

int main()
{
	int iCnt;
	iCnt=1;  // 아래 소스에서 for 함수로 정리 ⓐiCnt=1;
	
	while(10>iCnt) // for 함수 정리ⓑ(10>iCnt);  
	{
		printf("3 x %d = %d\n", iCnt, 3*iCnt);
		iCnt=iCnt+1;  // for 함수 정리ⓒiCnt=iCnt+1
	}
	return 0;
}
 


iCnt=iCnt+1


iCnt=++iCnt;


iCnt=iCnt++


을 위의 소스에 대입해도 모두 같은 결과 값을 얻을 수 있지만 첫번째가 권장된다.


처리속도는 동일하기에 소스를 짤 때 인간(프로그래머)이 보기에 헷갈리지 않게, 

보기 편하게 소스를 짜는 것이 좋다. 




이제 위의 소스를 for 함수를 사용해 정리해보자 (http://codepad.org/NhNOP5Qt)

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main()
{
	int iCnt;
		
	for(iCnt=1;10>iCnt;iCnt=iCnt+1)
	{
		printf("3 x %d = %d\n", iCnt, 3*iCnt);
	}
	return 0;
}



for (); 




for ()

{

}




for () {}


모두 같은 값을 얻을 수 있다.




두 소스 모두 output이 동일하다.


Output:

1
2
3
4
5
6
7
8
9
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27




volatile 변수


volatile 휘발성의


1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
 volatile int iCnt;  // volatile = 휘발성의
 for(;;) // = while(1)
 {
   for(iCnt=0;100000000>iCnt;iCnt=iCnt+1)
  { }
  printf("test\n");
 }
 return 0;
}



바로 위의 소스에서 volatile 변수를 쓰지 않는다면 CPU의 register내에서 모두 연산하고 Memory에 값을 저장하는 내부 최적화를 진행한다.


컴파일러가 자체적으로 메모리 접근을 최소화 시키는 것이다.


volatile은 이런 최적화를 하지않게 선언해서, CPU가 "매 값마다" 참/거짓을 판별, 연산하고 

메모리에 저장하고 가져오는 과정을 반복하게 한다.


명령창에서 실행해보면 volatile 변수를 쓴 것과 쓰지않은 것의 차이를 눈으로 확인할 수 있다.





UNION


여러 종류의 변수들을 같은 메모리 공간에 묶는다.


예제 소스 (http://codepad.org/vSaMCGCW)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

struct smart
{
    int A;
    short B;
    int C;
    char D;
};

int main()
{ 
    printf("Size of Smart: %d\n", sizeof(struct smart));
    
    return 0;
}


Output:

1
Size of Smart: 16




smart구조체를 UNION으로 수정 (http://codepad.org/rDFsMFkY

#include <stdio.h>

union smart 
//struct smart
{
    int A;
    short B;
    int C;
    char D;
};

int main()
{
    union smart obj;
    obj.A=0x12345678;
    obj.B=0x12345678;
    obj.C=0x12345678;
    obj.D=0x12345678;
 
  //printf("Size of Smart: %d\n", sizeof(struct smart));
    printf("Size of Smart: %d\n", sizeof(union smart));

    printf("%x\n", obj.A); 
    printf("%x\n", obj.B); 
    printf("%x\n", obj.C); 
    printf("%x\n", obj.D); 

    return 0;
}



Output:

1
2
3
4
5
Size of Smart: 4
12345678
5678
12345678
78


output 첫번째 줄을 보면 알 수 있듯이, size가 16에서 4로 바뀌었다.

smart 구조체를 union으로 바꿔주면 모두 4byte 안에 들어가게 된다. 

(int A; short B; int C; char D;)                         


각 데이터의 크기에 따라 각각 다른 값이 출력되게 되며, 다음과 같이 출력된다.


Little Endian

78 

 56

 34

 12


obj.A=12345678   // int A

obj.B=5678        // short B

obj.C=12345678  // int C

obj.D=78           // char D




함수 포인터를 사용하는 이유


①프로그램 코드의 간결


②중복 코드를 줄이기 위해서


③상황에 따라 해당되는 함수를 호출할 수 있음




type알아내기


type을 알아야 함수 포인터를 만들 수 있다.

아래와 같이 따라하면 원형에서 쉽게 type을 알아낼 수 있다.


1. void smart();   원형

2.        (*)

3. void (*) (); // void (*) ()가 type



int printf(const char *, ...);  // 원형

int (*)  (const char *, ...);  // Type



함수 포인터 예제 소스 (http://codepad.org/YiQTHzi9)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
void smart1()
{
 printf("1번함수\n");
}
void smart2()
{
 printf("2번함수\n");
}
int main()
{
 void (*test)( );
 test=smart1;
 test( );
 test=smart2;
 test( );
 return 0;
}


Output:

1
2
1번함수
2번함수


type 이름; 


1. void (*test) ();

2. test=smart1; 

3. test();




반도체 (Semi Conductor)


반/도체

Semi/Conductor


도체

전기 또는 열이 잘 통하는 물체


부도체

전기 또는 열에 대한 저항이 매우 커서 전기나 열을 잘 전달하지 못하는 물체


반도체

극성에 따라 전기가 흐르거나 흐르지 않는다.



마이크로 컨트롤러 제품군 중의 하나인 "AVR"


AVR 개발환경, Intel과 AVR의 교차개발 환경 구축을 위해 둘 사이에 WIN AVR이라는 컴파일러를 사용한다. 이를 Cross Compiler라고 한다.

윈도우에 visual studio가 있다면 avr은 avr studio가 있다.


아키텍처의 종류

RISC 

CISC  


장단점이 각각 있지만, 서로 단점을 보완하며 닮아가고 있다.




'Study > C' 카테고리의 다른 글

2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
20160329_C기초, 디버깅  (0) 2016.03.29
20160307_업무일지_파일 입출력  (0) 2016.03.07
728x90

- 파일 열기 


파일을 액세스하려면 먼저 대상 파일을 열어야(Open) 한다. 파일을 오픈한다는 것은 파일 입출력을 하기 위한 준비를 한다는 뜻이다. 

* 여기서 엑세스(Access)는 말 그대로 파일에 접근하는 것을 뜻한다.



스트림 입출력을 위해서는 파일의 데이터를 잠시 저장하는 내부 버퍼가 필요하며 파일의 현재 위치(FP)를 초기화해야 하는데 이런 준비를 하는 과정이 오픈이다. 

* Stream - 길이를 측정할 수 없는 특정한 data가 왔다갔다하는 것을 말하며, 이를 스트림 입출력이라고 한다. 

스트리밍 서비스의 음악, 동영상 감상 등이 이를 이용한 것이다. 받는 data의 양은 상황과 환경에 따라 유동적이다.


* 내부 버퍼 - 파일의 데이터를 잠시 임시로 저장하는 메모리 공간을 말한다.

모든 변수도 버퍼에 저장된다 볼 수 있다.


* 현재위치(File Pointer)  

                                   파일 (FILE)


탐색한다(SEEK) 

                         △ 여기서 파일을 탐색한 특정 지점을 FP라고 할 수 있다.




파일을 오픈할 때는 다음 함수를 사용한다. 

FILE *fopen(const char *filename, const char *mode);


먼저 인자의 갯수가 일치하는지 확인하고 인자의 Type이 서로 맞는지 확인한 다음, 최종적으로 반환값 일치여부를 확인한다.


  1.  #include <stdio.h>  
  2.   
  3. void smart(int Z); // int Z에서 type name Z는 컴파일에서 크게 중요하지 않음, 하지만 구분을 위해 의미있는 이름을 쓰기도 한다.  
  4.   
  5. int main()  
  6. {  
  7.     //FILE *fp;  
  8.     FILE *fp=fopen("A.txt""w");   
  9.     fprintf(fp, "파일입출력");  
  10.     //smart(printf);    
  11.     printf("파일입출력");  
  12.     fclose(fp);  // 파일을 닫음
  13.     return 0;  
  14. }  
  15. void smart(int A)  
  16. {  
  17. }  
다음의 예제 소스를 보자. 

파일경로에서 \\를 2개 쓰는 이유는 만약 \ 하나를 쓴다면 컴파일러에서 이를 개행(new line \n)으로 인식하고 컴파일하기 때문이다.

  1.  #include <stdio.h>  
  2.   
  3.   
  4. int main()  
  5. {  
  6.     FILE *f;  
  7.     f=fopen("c:\\영화\\코미디\\영구와땡칠이.avi","rb");  
  8.     if (f==NULL) {  
  9.                 printf("얼씨구. 파일이 안 보이네요\n");  
  10.              }  
  11.   
  12.     int fclose(FILE *stream);  // 사용한 stream 파일을 닫고, 버퍼를 비우게 된다.
  13.     return 0;  
  14. }  
컴파일 후 실행했을 때의 결과.

"c:\영화\코미디\" 디렉토리에 영구와땡칠이.avi 라는 파일을 읽을 수 없다면
(NULL) 을 리턴하고 ("얼씨구. 파일이 안 보이네요\n") 를 출력하게 된다.




여기서 도스 명령창을 통해 명령어와 절대 경로<->상대 경로를 배운다.

절대 경로가 변하지 않는 경로라면, 상대경로는 특정 위치를 기준으로 변화하는 경로이다. 



"c:\영화\코미디\"  디렉토리에서 cd c:\영화\ 명령어를 통해 이동한다면 

이는 절대경로를 이용한 것이다.




하지만 c:\영화\코미디\ 디렉토리에서 현재 위치를 기준으로 상위 디렉토리로 이동할 때,

cd .. 명령어를 통해 c:\영화로 이동할 수 있다. 

이는 상대경로를 이용한 것이다.



dir 명령어를 쳐보면 알 수 있지만 점 하나(.)는 은 현재 폴더 점 두개(..)는 상위 폴더를 의미한다.


도스, 윈도우즈에서는 대소문자의 구분을 하지 않으며, 여러 운영체제의 시초라고 할 수 있는 유닉스에서는 대소문자를 모두 구분한다.



개행 코드를 의미하는 CR/LF


ASCII 

 

 

 10

 CR

 Carriage Return

 18

 LF (\n)

 Line Feed


C언어에서 개행 코드를 의미하는 CR/LF 조합은 LF로 변환되어 읽혀지며 LF를 기록하면 CR/LF가 출력된다. 


CR(Carriage Return) : 커서를 맨 앞으로 이동한다. 

LF(Line Feed) : 다음 줄로 이동한다.


이런 변환을 해 주는 이유는 C 문자열 출력 함수들은 개행을 위해 확장열 LF(\n)를 사용하기 때문. 



파일의 끝을 의미하는 EOF = End Of File


Ctrl+Z(0x1A)는 EOF -1로 정의되며, 반환 파일의 끝을 표현하기 위한 상수 (-1)의 값을 지닌다.

명령어 Ctrl + Z는 ASCII Code로 0x1A이다.


안녕

하세요


-> 안 / 녕 / \n / 하 / 세 / 요 / 1A->EOF(-1)



NULL은 숫자 0을 의미

# define NULL 0

   주소  0을 리턴





실행파일을 2진파일(BIN)로 바꾸어서 열어보기


왼쪽부터 주소/ HEXA값 / ASCII 코드를 볼 수 있다. 헥사값을 바꿀시 아스키 코드도 따라서 바뀌는 것을 확인할 수 있을 것이다.




비트맵 파일(BMP)을 BIN파일로 바꾸고 열어보았을 때, HEXA값을 통해 파일의 확장자를 알 수 있다. 이를 MAGIC NUMBER라고 한다.



다음은 헥사값을 보기 위한 예제이다.


  1.  #include <stdio.h>  
  2.   
  3. void Hexaview(unsigned char *ucpData, unsigned int uiLen)  
  4. //void Hexaview(char *cpData, unsigned int uiLnt)  
  5. {  
  6.     unsigned int uiCnt;  
  7.     unsigned int ui16Cnt;     
  8.   
  9.     printf("====================Hexa Viewer============================\n");         
  10.     uiCnt=0;  
  11.     while(160>uiCnt)  
  12.     {  
  13.     printf("%p ", uiCnt);  
  14.   
  15.         ui16Cnt=0;  
  16.         while(16>ui16Cnt)  
  17.         {  
  18.             printf("%02x ", *ucpData);  // %02 -> 2자리로 출력하되 값이 없는 자리는 0으로 출력하라, %x는 16진수 출력을 의미
  19.             ui16Cnt=ui16Cnt+1;  
  20.             ucpData=ucpData+1;  
  21.         }         
  22.            
  23.         uiCnt=uiCnt+16;  
  24.         printf("\n");  
  25.     }  
  26.      printf("===========================================================\n");   
  27. }  
  28. int main()  
  29. {  
  30.     unsigned char ucBuff[ ]="1234567890ABCDEF";  // 헥사 값 16바이트. 즉, 한줄씩 저장되는 버퍼. 
  31.     //Hexaview(NULL, 0);  
  32.     Hexaview(ucBuff, 0);  
  33.     return 0;  
  34. }  

    cl hexa.c

    컴파일 후 실행 결과 


빨간선을 기준으로 왼쪽은 주소를 가리킨다. 아래로 내려오면서 16바이트씩 증가함을 볼 수 있다.

     오른쪽에 출력되는 부분은 아스키코드로 0x30은 문자 0이며, 0x31은 문자1과 같다.   (아스키 코드표 http://www.asciitable.com/)


    






'Study > C' 카테고리의 다른 글

2016-04-06-업무일지_포인터 및 함수  (0) 2016.04.06
20160405_포인터와 배열  (0) 2016.04.05
20160401_전역변수와 포인터  (0) 2016.04.04
20160329_C기초, 디버깅  (0) 2016.03.29
20160308_업무일지_그 밖의 기초 학습  (0) 2016.03.08

+ Recent posts