공부했던 자료 정리하는 용도입니다.

재배포, 수정하지 마세요.

 

 


 문자열 

  • 문자열을 할당하는 방식
    1. 문자열 리터럴을 포인터에 할당하는 방식
    2. 문자 배열에 할당하는 방식

 

 문자, 문자열 관련 함수 

  1. 문자 단위 입출력 함수
    • 문자 입력 함수 : getchar, fgetc
    • 문자 출력 함수 : putchar, fputc
      * 문자 입출력의 EOF
  2. 문자열 단위 입출력 함수
    • 문자열 입력 함수 : gets, fgets
      * 정해진 크기보다 많이 입력하는 경우(fgets)
      * \n이 포함된 경우
    • 문자열 출력 함수 : puts, fputs
  3. 입출력 이외의 문자열 관련 함수
    • 문자열 길이 반환 : strlen
      * fgets에서 enter(개행 문자, \n) 제외하고 받기
    • 문자열 복사 : strcpy, strncpy
    • 문자열 덧붙이기 : strcat, strncat
    • 문자열 비교 : strcmp, strncmp
  4. 변환 함수
    • 문자열 데이터 변환 함수 : atoi, atol, atof

 


 

문자열

  c언어에서는 문자열 끝에 항상 널 문자(NULL)가 붙는다. (\0으로도 표현 가능)

 

 

문자열을 할당하는 방식

  1. 문자열 리터럴을 포인터에 할당하는 방식

char *s = "hello";
printf("%p\n", s);	// 문자열이 저장된 메모리 출력

  문자열 리터럴을 포인터에 할당하면 문자열 리터럴이 변수 안에 저장되는 것이 아니라 문자열이 있는 곳의 메모리 주소만 저장된다. 또한 이 문자열 리터럴이 있는 메모리 주소는 읽기 전용이므로 다른 문자열을 덮어쓸 수 없다. (C언어 컴파일러는 문자열 포인터에 할당한 문자열 리터럴을 실행파일의 읽기 전용 데이터 섹션(데이터 세그먼트)에 배치한다. 따라서 실행 파일이 실행된 뒤에는 읽기 전용 메모리가 되며 쓰기를 할 수 없다. 읽기 전용 데이터 섹션의 이름은 운영체제별로 다르다.)

  • Windows PE : .rdata
  • 리눅스 ELF : .rodata
  • OS X Mach-O : __TEXT, __cstring

 

  - 문자열 리터럴의 최대 크기
  c언어 표준에는 최소 4095문자로 정의되어 있으며 Visual Studio 2015는 최대 2048 byte, GCC는 4095문자까지 사용 가능하다.

 

 

 

  2. 문자 배열에 할당하는 방식

char s[10] = "hello";	// 크기가 10인 char형 배열을 선언하고 문자열 할당
printf("%s\n", s);	// 문자열 출력

// 배열의 크기를 생략하는 경우
char str[] = "hello";	// 문자 배열을 선언하면서 문자열을 바로 할당할 때는 배열크기 생략가능

  문자열을 배열에 저장하는 방식은 배열 요소 하나하나에 문자가 저장된다. (남는 공간에는 모두 NULL이 들어간다.) 배열의 크기는 할당할 문자열보다 크게 지정해야 한다. 또한 배열을 선언한 즉시 문자열로 초기화해야 한다. (선언만 해놓고 나중에 할당할 수 없다. 굳이 할당할 경우 배열 요소 하나하나에 문자를 넣어야 한다.)

 

 

 

 

 


문자, 문자열 관련 함수

1. 문자 단위 입출력 함수

  ``printf``와 ``scanf`` 함수는 포맷을 지정해서 출력하는 함수이기 때문에 사용하는 메모리 공간도 크고, 해야 할 연산의 양도 많아 상대적으로 속도가 느리다. 또한 별도의 서식 지정을 해야 하기 때문에 문장을 구성하는 것도 번거로운 편이다. 그래서 단순히 문자 하나를 입출력하는 것이 목적이라면 문자 단위 입출력 함수를 사용하는 것이 더 낫다.

 

 

  ■ 문자 입력 함수 : getchar, fgetc

#include <stdio.h>
int getchar(void);
int fgetc(FILE * stream);

키보드로부터 하나의 문자를 입력받을 때 일반적으로 사용하는 함수들이다.

파일에 끝에 도달하거나 함수 호출 실패 시 ##EOF##를 반환한다.

(``EOF``가 ``-1``로 정의된 상수이기 때문에 문자와 관련된 함수임에도 반환형이 ``int``이다.)

 

  • ``getchar`` : ``stdin``(표준 입력 스트림)으로 부터 하나의 문자를 입력받아 반환하는 함수
  • ``fgetc`` : ``getchar``와 기능은 같지만 문자를 입력받을 스트림을 지정할 수 있다.

 

 

 

  문자 출력 함수 : putchar, fputc

#include <stdio.h>
int putchar(int c);
int fputc(int c, FILE * stream);	// 두 번째 매개변수인 stream이 문자를 출력할 스트림 지정에 사용됨

모니터로 하나의 문자를 출력할 때 일반적으로 사용하는 함수들이다. 

함수 호출 성공 시 쓰인 문자정보, 실패 시 ##EOF##를 반환한다.

 

  • ``putchar`` : 인자로 전달된 문자정보를 ``stdout``(표준 출력 스트림)으로 전송하는 함수
  • ``fputc`` : ``putchar`` 함수와 동일한 기능을 하지만 문자를 전송할 스트림을 지정할 수 있다. (``stdout``뿐만 아니라, 파일을 대상으로도 데이터 전송 가능) 

 

#include <stdio.h>

int main(void)
{	
	int ch1, ch2;
	
	ch1 = getchar();	// 문자 입력 
	ch2 = fgetc(stdin);	// enter키 입력 
	
	putchar(ch1);		// 문자 출력 
	fputc(ch2, stdout);	// enter키 출력 
	
	return 0;		
}

문자 단위 입출력 함수를 사용하는 예시이다.

 

실행 결과(입력 값에 따라 달라짐)

결과에는 문자 하나만 보이지만 실제로는 ``enter``키까지 2개의 문자가 입출력된 것이다.

@@enter@@키도 아스키코드 값이 @@10@@인 @@\n@@으로 표현되는 문자이기 때문에 입출력의 대상이 된다.

 

 

   문자 입출력의 EOF 

  ``EOF``는 End Of File의 약자로, 파일의 끝을 표현하기 위해 정의된 상수이다. 파일의 ``EOF``는 파일의 끝을 의미하지만 ``fgetc``와 ``getchar`` 함수는 아래에 있는 두 가지 조건중 하나가 만족되면 ``EOF``를 반환한다.

 

   fgetc 함수와 getchar 함수가 EOF를 반환하는 경우 

  1. 함수 호출의 실패
  2. 다음의 키가 입력되는 경우
    Window에서 ``Ctrl + z`` 
    Linux에서 ``Ctrl + d``

 

#include <stdio.h>

int main(void)
{	
	int ch;
	
	while(1)
	{
		ch = getchar();
		if(ch == EOF)	// 입력이 EOF가 될 경우 무한루프 종료
			break;
		putchar(ch);
	}
	 
	return 0;		
}

입력이 ``EOF``가 되기 전까지 계속해서 문자를 입력받고 출력하는 예시이다.

 

실행 결과(Window)

  Window에서 실행하면 ``Ctrl + z``했을 때 프로그램이 종료된다. ``getchar( )``이 반복문 안에 들어갔기 때문에 여러 개의 문자를 입력(공백 포함) 해도 문자의 수만큼 ``getchar`` 함수가 호출되면서 모든 문자를 읽어 들인다.

 

 

 

2. 문자열 단위 입출력 함수

  ``scanf`` 함수는 공백을 기준으로 문자열을 구분하기 때문에 공백이 포함된 형태의 문자열을 입력받는데 제한이 있다. 하지만 문자열 단위 입출력 함수를 사용하면 공백을 포함하는 문자열도 입력받을 수 있다.

 

 

  문자열 입력 함수 : gets, fgets

#include <stdio.h>
char * gets(char * s);
char * fgets(char * s, int n, FILE * stream);
// gets 함수 사용 예시
char str[7];
gets(str);	// 입력받은 문자열을 배열 str에 저장


// fgets 함수 사용 예시
char str[7];
fgets(str, sizeof(str), stdin);	// stdin으로부터 문자열을 입력받아 str의 길이만큼 str에 저장 (null문자 포함이므로 실제로는 arr - 1 길이)

키보드로부터 하나의 문자열을 입력받을 때 일반적으로 사용하는 함수들이다.

파일의 끝에 도달하거나 함수 호출 실패 시 ##NULL## 포인터를 반환한다.

 

  • ``gets``의 경우 배열을 넘어서는 길이의 문자열이 입력되면 할당받지 않은 메모리 공간을 침범하여 실행 중 오류가 발생하므로 가급적 ``fgets`` 함수를 호출하는 것이 좋다.
  • 문자열 중간에 삽입된 공백 문자도 문자열의 일부로 받아들인다.
  • ``fgets``는 @@\n@@을 만날 때까지 문자열을 읽어 들이는데, @@\n@@을 문자열의 일부로 받아들인다.
  • ``fgets``로 문자열을 입력받으면 문자열의 끝에 자동으로 null 문자가 추가된다.
    ex) 두 번째 인자가 ``n``이면 실제 들어가는 문자열의 개수는 ``n - 1``

 

 

  - 정해진 크기보다 많이 입력하는 경우 (fgets)

#include <stdio.h>

int main(void)
{	
	char str[7];
	
	for(int i = 0 ; i < 3 ; i++)
	{
		fgets(str, sizeof(str), stdin);
		printf("Read %d : %s \n", i + 1, str);
	}
	
	return 0;		
}

 

실행 결과 1

  입력받을 ``str``의 크기는 ``7``인데 입력된 문자열의 길이가 배열의 크기를 넘어선 경우 입력 버퍼에 남아있던 값들이 멋대로 ``fgets`` 함수의 인자로 들어가게 된다. (##null## 제외 ##6##개씩 들어감) 결과값을 보면 아직도 ``9``와 ``0``이 버퍼에 남아있는 것을 확인할 수 있다. 버퍼를 비우려면 ``fgets`` 함수를 더 호출하거나 입력 버퍼를 비워야 의도한 대로 입력을 ``3``번 받을 수 있다.

 

 

  - \n이 포함된 경우

실행결과 2

  바로 위에서 실행한 예제에 입력값을 바꾼 것이다. ``fgets`` 함수는 ``\n``을 만날 때까지 문자열을 읽어 들이는데, 읽어 들이고 난 후 ``\n``을 제외하거나 버리지 않고 문자열의 일부로 받아들인다. 그래서 printf 함수에는 개행 문자가 한 번만 사용됐지만 실제로는 문자열에 포함된 ``\n``까지 ``2``번 개행되었다. 문자열 중간의 공백도 마찬가지이다.

 

 

 

  ■ 문자열 출력 함수 : puts, fputs

#include <stdio.h>
int puts(const char * s);
int fputs(const char * s, FILE * stream);	// 두 번째 인자를 통해 출력의 대상을 지정할 수 있다.

모니터로 하나의 문자열을 출력할 때 일반적으로 사용하는 함수들이다.

함수 호출 성공 시 음수가 아닌 값을, 실패 시 ##EOF##를 반환한다.

 

  • ``puts`` : ``stdout``을 대상으로 출력. 출력 후 자동 개행
  • ``fputs`` : ``puts``와 기능은 같지만 출력의 대상 지정 가능. 출력 후 자동 개행 X

 

#include <stdio.h>

int main(void)
{	
	char * str = "Simple String";
	
	printf("1. puts test ------- \n");
	puts(str);				// 문자열의 주소값 전달
	puts("So Simple String");
	
	printf("2. fputs test ------- \n");
	fputs(str, stdout); 			// 문자열의 주소값 전달, 출력 대상을 stdout 스트림으로 지정
	printf("\n");				// fputs는 자동 개행이 되지 않기 때문에 별도의 개행 작업이 필요함
	fputs("So Simple String", stdout);
	printf("\n");				// fputs는 자동 개행이 되지 않기 때문에 별도의 개행 작업이 필요함
	
	printf("2. end of main ------- \n");
	
	return 0;		
}

``puts``와 ``fputs``의 차이점을 확인하는 예시이다.

@@puts@@함수와 달리 @@fputs@@ 함수는 자동 개행이 되지 않기 때문에 함수 호출 후 별도의 개행 작업을 해야 한다.

 

실행 결과

 

 

 

 

3. 입출력 이외의 문자열 관련 함수

  표준 C에서는 문자열과 관련된 다양한 함수가 정의되어 있다. 아래의 함수들은 헤더 파일 @@string.h@@에 선언된 문자열 관련 함수들이다.

 

 

  ■ 문자열의 길이 반환 : strlen

#include <string.h>
size_t strlen(cons char * s);

인자로 전달된 문자열의 길이를 반환하는 함수이다. (@@null@@은 길이에서 제외)

  이 함수의 반환형인 ``size_t``는 ``typedef unsigned int size_t``로 선언되어 있으므로 본래는 ``unsigned int``형 변수에 저장하고 서식 문자 ``%u``로 출력하는 것이 정확하나, 반환 값을 ``int``에 저장하고 서식 문자 ``%d``로 출력하는 것이 일반적이다.

 

 

  - fgets에서 enter(개행 문자, \n) 제외하고 받기

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

void RemoveBSN(char str[])
{
	int len = strlen(str);
	str[len - 1] = 0;	// \n이 저장된 위치에 null문자 삽입
}

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

  ``fgets``는 ``\n``까지 문자열의 일부로 받아들이기 때문에, 입력받은 문자열의 길이를 계산해서 ``\n``이 저장된 위치에 널 문자의 아스키코드값인 ``0``을 넣어 ``\n``을 제거하는 방법도 있다.

 

실행 결과

 

 

  ■ 문자열 복사 : strcpy, strncpy

#include <string.h>
char * s strcpy(char * dest, const char * src);
char * s strncpy(char * dest, const char * src, size_t n);
// strcpy 함수 사용예시
char str1[30] = "Simple String";
char str2[30];
strcpy(str2, str1);

// strncpy 함수 사용 예시
strncpy(str2, str1, sizeof(str2));	// str1의 문자열을 str2의 크기만큼 str2에 복사

문자열의 복사에 사용되는 함수들이다. 복사된 문자열의 주소 값을 반환한다.

 

  • ``strcpy`` : 문자열 복사. 문자열이 복사될 배열의 길이가 문자열의 길이보다 작지 않도록 주의해야 한다.
  • ``strncpy`` : 세 번째 인자 값만큼 문자열 복사. (복사될 배열의 길이를 넘어서지 않는 범위 내에서 복사할 때 유용하게 사용됨.) 그러나 문자열을 단순하게 값만큼 복사하기 때문에 세 번째 인자에 값을 넣을 때는 배열의 실제 길이보다 @@1@@ 작은 값을 전달해서 @@null@@문자가 삽입될 공간을 남겨두고 복사를 진행한 뒤, 끝에 @@null@@문자를 삽입해야 한다.

 

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

int main(void)
{	
	char str1[20] = "1234567890";
	char str2[20];
	char str3[5];
	
	// case 1
	strcpy(str2, str1);
	puts(str2);
	
	// case 2
	strncpy(str3, str1, sizeof(str3));
	puts(str3);
	
	// case3
	strncpy(str3, str1, sizeof(str3) - 1);
	str3[sizeof(str3) - 1] = 0;
	puts(str3);
	
	return 0;
}

``strcpy``와 ``strncpy``를 사용하는 예시이다.

 

실행 결과

  case 2의 ``str3``은 ``null``문자가 들어갈 자리를 고려하지 않고 배열의 크기만큼 복사를 진행했기 때문에 문자열 끝에 ``null``문자가 없어져 버렸다. 그래서 16행에서 출력할 때 문자열 출력이 끝나지 않고 이상한 값이 계속 출력되는 것이다. case 3처럼 복사를 진행하고 배열의 끝에 ``null``문자를 삽입해야 제대로 복사가 진행된다.

 

 

  ■ 문자열 덧붙이기 : strcat, strncat

#include <string.h>
char * strcat(char * dest, const char * src);
char * strncat(char * dest, const char * src, size_t));

문자열의 뒤에 다른 문자열을 복사하는 함수이다. 덧붙여진 문자열의 주소 값을 반환한다.

 

  • 덧붙이는 위치는 ``null``문자 다음이 아닌 ``null``문자가 저장된 위치이다. (그래야 붙인 이후에도 ##null##문자가 하나가 됨)
  • @@strncat@@에서 세 번째 인자가 @@8@@이면 @@null@@문자를 제외한 @@8@@만큼이라는 의미이다. 붙여질 때는 문자열 끝에 @@null@@문자가 자동으로 삽입되어 9개의 문자가 덧붙여진다.

 

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

int main(void)
{	
	char str1[20] = "First~";
	char str2[20] = "Second";
	
	char str3[20] = "Simple num : ";
	char str4[20] = "1234567890";
	
	// case 1
	strcat(str1, str2);	// str1의 크기가 str2를 덧붙일 수 있을 만큼 커야함
	puts(str1);
	
	// case 2
	strncat(str3, str4, 7);
	puts(str3);
	
	return 0;
}

``strcat``과 ``strncat``을 사용하는 예시이다.

 

실행 결과

 

 

  ■ 문자열 비교 : strcmp, strncmp

#include <string.h>
int strcmp(const char * s1, const char * s2);
int strncmp(const char * s1, const char * s2, size_t n);

  문자열을 ``==``연산자로 비교해버리면 문자열의 내용을 비교하는 것이 아니라 문자열의 주소 값을 비교하는 것이 되어버린다. 그래서 문자열을 비교할 때는 위의 함수를 사용해야 한다. 문자(문자열 끝의 ##null##문자까지 포함)를 아스키 값으로 비교해서 두 문자열의 내용이 같으면 ##0##, 다르면 ##0##이 아닌 값을 반환한다.

 

  • ``strcmp`` : 문자열 비교
  • ``strncmp`` : ``strcmp``와 같지만 세 번째 인자로 전달된 수의 크기만큼만 문자를 비교

 

#include <stdio.h>
#include <string.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을 반환. if문에서 0은 false이므로 !연산하면 true가 됨.
		puts("두 문자열은 동일");
	else
	{
		puts("두 문자열은 동일하지 않음");
		
		if(!strncmp(str1, str2, 3))	// 두 문자열이 같으면 0을 반환. if문에서 0은 false이므로 !연산하면 true가 됨.
			puts("그러나 앞 세 글자는 동일");
	}
	
	return 0;
}

``strcmp``와 ``strncmp``를 사용해서 문자열을 비교하는 예시이다.

두 함수 모두 문자열이 같을 때 @@0@@을 반환하는데, C언어에서는 @@0@@이 @@false@@를 의미하므로 @@!@@연산을 하면 @@true@@가 된다.

 

실행 결과

 

 

 

4. 변환 함수

  @@stdlib.h@@에 선언된 함수이다.

 

 

  ■ 문자열 데이터 변환 함수 : atoi, atol, atof

int atoi(const char * str);	// 문자열 내용을 int형으로 변환
long atol(const char * str);	// 문자열 내용을 long형으로 변환
double atof(const char * str);	// 문자열 내용을 double형으로 변환

문자열로 표현된 정수나 실수 값을 해당 정수나 실수 데이터로 변환해야 하는 경우 사용한다.

 

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

int main(void)
{	
	char str[20];
	
	printf("정수 입력 : ");
	scanf("%s", str);
	printf("%d \n", atoi(str));
	
	printf("실수 입력 : ");
	scanf("%s", str);
	printf("%g \n", atof(str));
	
	return 0;
}

변환 함수를 사용하는 예시이다.

 

실행 결과

 

 

 

'기타 > C' 카테고리의 다른 글

[C] 공용체(Union Type), 열거형(Enumerated Type)  (0) 2020.06.08
[C] 구조체  (0) 2020.06.01
[C] 스트림, 버퍼  (0) 2020.05.27
[C] 함수 포인터, void 포인터  (0) 2020.05.22
[C] 다차원 배열과 포인터  (0) 2020.05.19

+ Recent posts