따배씨 4. 문자열과 형식 맞춘

4.1 스트링 I/O

char fruit_name; // 하나의 문자만 저장

printf("What is your favorite fruit?");

scanf("%c", &fruit_name);

printf("You like %c!
\n", fruit_name);
char fruit_name(40);

printf("What is your favorite fruit?");

scanf("%s", fruit_name);

printf("You like %s!
\n", fruit_name);

fruit_name 자체는 배열을 나타내는 주소이므로 앞에 &를 붙일 필요가 없습니다.

4.2 오퍼레이터의 규모

int a = 0;
unsigned int int_size1 = sizeof a;
unsigned int int_size2 = sizeof(int);
unsigned int int_size3 = sizeof(a);

size_t int_size4 = sizeof(a);
size_t float_size = sizeof(float);

배열 크기

int int_arr(30);  
int *int_ptr = NULL;  // 배열의 주소값을 적을 수 있는 공간
int_ptr = (int*)malloc(sizeof(int) * 30);  // 메모리를 받아서 그중 대표하는 메모리를 하나 받아서 적음

printf("Size of array = %zu bytes\n", sizeof(int_arr));  // 배열의 크기, 120bytes
printf("Size of pointer = %zu bytes\n", sizeof(int_ptr));  // 배열 주소를 적는 공간의 크기, 4bytes

문자열 배열의 크기

char c="a";
char string(10); // 맨 끝에 '/0'가 들어가기 때문에 최대 9개 문자 수용

size_t char_size = sizeof(char);  // 1 bytes
size_t str_size = sizeof(string);  // 10 bytes

printf("Size of char type is %zu bytes.\n", char_size);
printf("Size of string type is %zu bytes.\n", str_size);

구조의 크기

struct MyStruct
{
    int i;
    float f;
};

int main()
{

printf("%zu\n", sizeof(struct MyStruct));  // 8byte(int 4, float 4)

};

4.3 문자열이 메모리에 저장되는 구조

문자열의 끝을 ‘\0′(널 문자)로 표시한 다음 아무 것도 출력하지 마십시오.

int a = 1;
int int_arr(10) = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

printf("%i %i %i\n", int_arr(0), int_arr(1), int_arr(9));

printf("%i\n", int_arr(10000));
// 인덱스가 배열의 크기를 넘어서기 때문에 err

char c="a";
char str1(10) = "Hello";  // null character 때문에 크기는 6byte
// 문자열을 초기화할 때는 큰따옴표 사용
char str2(10) = { 'H', 'i' }; // 다른 방식으로 초기화

printf("%c\n", c);
printf("%s\n", str1);
printf("%s\n", str2);

printf("%hhi, %hhi, %hhi, %hhi\n", str2(0), str2(1), str2(2), str2(3), str2(4));
// 72 (H 아스키 코드) 105 (i 아스키 코드) 0 0 0 출력

char str3(10) = "Hello, World"; // 배열 크기가 충분하지 않아 err
char str3(20) = "Hello, \0World"; // printf함수에서 \0이후로 출력하지 않음, 실제로는 배열에 저장되어 있음
printf("%s\n", str3);

4.4 strlen() 함수

char str1(100) = "Hello";
char str2() = "Hello";
char str3(100) = "\0";
char str4(100) = "\n";

printf("%zu %zu\n"n sizeof(str1), strlen(str1)); // zu를 지원하지 않는 컴파일러도 간혹 존재, 100 5 출력
printf("%zu %zu\n"n sizeof(str2), strlen(str2)); // 6 5 출력
printf("%zu %zu\n"n sizeof(str3), strlen(str3)); // 100 0 출력
printf("%zu %zu\n"n sizeof(str4), strlen(str4)); // 100 1 출력

strlen() 함수는 null이 아닌 문자의 수를 계산합니다.

/*동적할당 예시*/
char *str5 = (char*)malloc(sizeof(char) * 100);
str(0) = 'H'; str(1) = 'e'; str(2) = 'l'; str(3) = 'l'; str(4) = 'o';
str(5) = '\0';
printf("%zu %zu\n", sizeof(str5), strlen(str5)); // 4 5 출력

4는 포인터 변수 자체의 크기입니다.


5는 문자 수입니다.

4.5 기호 상수 및 전처리기

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define PI 3.141592f
#define AI_NAME "Friday"

int main()
{

    float radius, area, circum;

    printf("I'm %s.\n", AI_NAME);
    printf("Input radius\n");

    scanf("%f", &radius);

    /*
    area = 3.141592f * radius * radius; // area = pi * r * r
    circum = 2.0 * 3.141592f * radius; // circum = 2.0 * pi * r
    // 리터럴(상수)를 기호적 상수로 바꿔 사용하면 보기에도 깔끔하고 실수할 가능성도 줄음
    */

    area = PI * radius * radius; // area = pi*r*r
    circum = 2.0 * PI * radius; // circum = 2.0 * pi * r

    printf("Area is %f\n", area);
    printf("Circumference is %f\n", circum);


    return 0;
}

컴파일러의 관점에서 기호 상수는 해당 상수로 대체하여 처리됩니다.

즉 인간을 위한 기능이다.

#define PI = 3.141592f
#define AI_NAME = "Friday"

덮어쓰지 않도록 주의

함수 내에서 정의할 수 있지만 나중에 변수의 상수 값을 다른 값으로 변경하면 오류가 발생할 수 있습니다.

const float pi = 3.141592f;
float const pi = 3.141592f;

최근에는 후자의 경우를 추천한다.

4.6 매니페스트 상수

매니페스트(분명하고 명백한) 상수, 기호 상수, 매니페스트 상수

limits.h(데이터 유형의 최대 범위를 미리 선언한 헤더) 등


-정의

4.7 printf() 함수의 변환 식별자

printf("제어-문자열", 아이템1, 아이템2, ...) 변수, 상수, 표현식 등
printf("%d + %d = %d", 1, a, 1 + a);

형식 지정자

전환 식별자

%(flags)(width)(p.precidion)(length)specifier
printf("%+10.5hi", 256);
double d = 3.14159265358979323;

// 한글자, '' 표시
printf("%c\n", 'A');
printf("%s", "I love you");
printf("Even if there's a small chance, \
we owe this to everyone who's not in this room to try.\n");

printf("\n");
// signed decimal integer
printf("%d %i %i %i\n", 1004, 1234, INT_MAX, UINT_MAX); // overflow 발생하여 -1 출력
printf("%u %u %u\n", 1024, -1, UINT_MAX); // overflow 발생하여 -1 출력

printf("\n");
// 부동 소수점 수, 10진수
printf("%f %f %lf\n", 3.141592f, d, d); // l 무시됨, printf 함수에서 float형을 출력할 때 double형으로 바꾸기 때문에 
// 부동 소수점 수, 16진수, p-표기법 
printf("%a %A\n", d, d);
// 부동 소수점 수, 16진수, P-표기법
printf("%e %E\n", d, d);

printf("\n");
// 부동 소수점 수, %e, %f처럼 보여줌(더 짧은 것), 지수가 -4보다 작거나 정밀도보다 크거나 같을 경우에는 %e
printf("%g %g\n", 123456.789, 1234567.89); // 1234567 1.23457e+06
// 부동 소수점 수, %E, %F처럼 보여줌(더 짧은 것), 지수가 -4보다 작거나 정밀도보다 크거나 같을 경우에는 %E
printf("%G %G\n", 123456.789, 1234567.89); // 1234567 1.23457E+06
printf("%g %g\n", 0.00012345, 0.000012345); // 0.00012345 1.2345e-05
printf("%G %G\n", 0.00012345, 0.000012345); // 0.00012345 1.2345E-05

printf("\n");
// unsigned octal integer
printf("%o\n", 9); // 11 
// pointer
printf("%p\n", &d); // 이 변수가 사용하고 있는 메모리의 주소 출력

printf("\n");
// 16진수 
printf("%x %X\n", 11, 11); // b B 출력
printf("%%\n", d); // d는 무시됨, % 출력

printf("\n");
printf("%9d\n", 12345); // 최소 9자리로 출력
printf("%09d\n", 12345); // 최소 9자리로 출력하는데 빈자리는 0으로 채움
printf("%.2f\n", 3.141592); // 소수점 2번째자리까지 출력
printf("%.20f %.f20lf\n", d, d);

printf("\n");
int n_printed = printf("Counting"); // printf 함수의 리턴값은 출력한 글자수
printf("%u\n", n_printed); // 9 출력

4.8 변환 지정자를 위한 수정자

%(flags)(width)(p.precidion)(length)specifier
printf("%+10.5hi", 256);

깃발

여러 옵션 중 하나를 선택하려면

링크 삽입(왼쪽 정렬)
그렇지 않다면 맞다
너비와 함께 사용해야 합니다.

+ 긍정적인 경우에도 표시 표시
그렇지 않은 경우 음수인 경우에만 부호 표시
비어 있는 긍정적인 경우 비어 있음
# 8진수와 16진수를 출력할 때 0과 0x를 함께 출력합니다.


지정자 o, x, X, a, A, e, E, f, F, g, G 등과 함께 사용됩니다.

0 너비가 지정되면 나머지 공간은 0으로 채워집니다.

넓은

숫자 인쇄할 최소 문자 크기입니다.

이 숫자보다 작으면 공백으로 채워집니다.

*

.정도

.숫자 최소 출력 정밀도와 자릿수를 보장하며, 숫자가 충분하지 않으면 0으로 채웁니다.

.*

길이

데이터 유형의 길이

printf("%10i\n", 1234567);  //   1234567
printf("%-10i\n", 1234567);  //1234567
printf("%+i %+i\n", 123, -123);  //+123 -123
printf("% i \n% i\n", 123, -123);  // 123,-123
printf("%X\n", 17);  //11
printf("%#x\n", 17);  //0x11
printf("%05i\n", 123);  //00123
printf("%*i\n", 7, 456);  //    456

printf("\nPrecision\n");
printf("%.3d\n", 1024);  //1024
printf("%.5d\n", 1024);  //01024
printf("%.3f\n", 123456.1234567);  //123456.123
printf("%.3f\n", 123456.1235);  //123456.124(반올림)
printf("%10.3f\n", 123.45678);  //   123.457(반올림)
printf("%010.3f\n", 123.45678);  //000123.457(반올림)
printf("%.5s\n", "ABCDEFGHIJKLMN");  //ABCDE
printf("%.s\n", "ABCDEFGHIJKLMN");  //

printf("\nLength\n");
printf("%hhd %hd %d\n", 257, 257, 257);  //1(오버플로우 발생) 257 257
printf("%d %lld %lld\n", INT_MAX + 1, INT_MAX + 1, 2147483648LL);  //-2147483648 2147483648 2147483648

4.10 scanf() 함수 사용

* : 무시하다

개수: 입력을 받을 수 있는 최대 너비

hh: 부호 있는 문자 또는 부호 없는 문자로 정수 읽기

ll: 정수를 long long 또는 unsigned long long으로 읽습니다.

h, l, L: %hd(%hi) -> 짧은 정수

%ho, %hx, %hu -> unsigned short int (%d, %i, %o, %x -> int)

%ld, %li -> 길다

%lo, %lx, %lu -> unsigned long

%le, %lf, %lg -> double(%e, f, %g -> float)

%Le, %Lf, %Lg -> 롱 더블

j: 데이터 유형 intmax_t 또는 uintmax_t(C99)

z: sizeof 연산자 반환 값의 데이터 유형

t: 두 포인터의 차이(C99)

입력을 받고 입력을 출력하는 것은 모두 scanf가 하는 일입니다.

/* multiple inputs with blank separators */

int i;
float f;
char str(30);
scanf("%d %f %s", &i, &f, str); // 문자열 앞에는 % 안붙음 % is absent in front of str
printf("%d %f %s\n", i, f, str);

/* character 
*  문자 입력 시 빈칸도 문자로 입력받음, 아스키코드 32
*/
char c;
scanf("%c", &c);
printf("%i\n", c);

/* Unsigned as signed 
*  음수를 넣었을 때 정상으로 나옴
*  unsigned인데 받을 때 signed로 받아 unsigned 메모리에 저장해뒀다가 signed로 꺼내서 -가 그대로 붙어 나옴, 비추
*/
unsigned i;
scanf("%i", &i);
printf("%i\n", i);

/* Unsigned as unsigned 
*  음수를 넣으면 오버플로우 발생하여 엉뚱한 값이 나옴
*/
unsigned i2;
scanf("%u", &i2);
printf("%u\n", i2);

/* floating point numbers */
// l for double for %f, %e, %E, %g
double d = 0.0;
scanf("%lf", &d);  // lf, try E notation
printf("%f\n", d);  // double 형에는 lf 변환지정자를 써야 함

/* Width 
*  어느 자리까지 입력을 받을 것인지 설정 가능
*/
char str(30);
scanf("%5s", str);  // 5번째 자리까지 입력받을 수 있음
printf("%s\n", str);

char i;
scanf("%hhd", &i);  // 변수와 변환지정자 타입을 잘 맞춰줘야 함
printf("%i\n", i);

/* 문자와 정수를 함께 사용 
*  -> 문자 시작점부터	잘라서 i에 넣어줌
*/
int i;
scanf("%i", &i);
printf("%i\n", i);

/* j modifier
*  intmax_t를 받는다는 의미로 j를 써줌 portable type
*/
intmax_t i;
scanf("%ji", &i);
printf("%ji", i);

/* regular characters, 정규식 */
int a, b;
scanf("%d,%d", &a, &b); // 입력시 해당하는 글자를 같이 넣어줘야 scanf가 제대로 인식, 공백 갯수는 상관 없음
scanf("%d ,%d", &a, &b);
scanf("%d, %d", &a, &b);
scanf("%d,%d", &a, &b);
scanf("%d-%d", &a, &b);
scanf("%dA%d", &a, &b);
printf("%d %d\n", a, b);

/* char recieve blank */
int a, b;
char c;
scanf("%d%c%d", &a, &c, &b);  // 123A456 입력시
scanf("%d|%c|%d", &a, &c, &b);  // 123|A|456 출력

// sentence, getchar() fgets(), etc.

/* scanf의 return 값 
*  item을 몇개나 입력받았는가
*/
int a, b;
int i = printf("%d%d", &a, &b);  // i = 2
printf("%d", i); 

/* printf()를 위한 *변환지정자 (modifier) */
int i = 123;
int width = 5;  // from script, file, scanf, etx.
printf("Input width : ");
scanf("%d", &width);
printf("%*d\n", width, i); // width가 *에, i가 d에 들어가게 됨 
/*width가 1이면 123 다 출력, 5면 '  123' 출력*/

/* scanf()를 위한 *변환지정자 (modifier) */
int i;
scanf("%*d%*d%d", &i);  /* *붙은 modifier는 넘어가고 마지막만 저장
scanf가 빈칸이나 줄바꿈을 찾아 인식하고 중간에 다른 기호가 있는 경우 기호와 빈칸 조합하여 진행
123 456 789 입력시 i에 789 저장 */
printf("Your third input = %d", i);