본문 바로가기

programming language/C 언어

열혈 ( C ) chapter 21 정리노트 2

chapter21-3

 

문자열 출력 함수: puts, fputs

#include<stdio.h>
int puts(const char * s);
int fputs(const char*s,FILE * stream);

puts 함수는 출력의 대상이 stdout으로 결정되어 있지만, fputs 함수는 두 번째 인자를 통해서 출력의 대상을 결정할 수 있다. 그리고 둘 다 첫 번째 인자로 전달되는 주소 값의 문자열을 출력을 한다. 

 

<예제>

#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); printf("\n");
	fputs("so simple string", stdout); printf("\n");

	printf("3. end of main -----\n");
		return 0;
}

puts 함수의 호출이 있고, 문자열이 선언된 위치에는 문자열의 주솟값이 반환되므로, 두 경우 모두 문자열의 주소 값이 반환이 된다. 즉 그 주솟값에 해당하는 문자열을 출력한다.

fputs 함수의 호출이 있고, 두번쨰 인자로 stdout이 전달이 됐으므로, 모니터로 출력이 된다.

 

실행결과를 보면 puts함수가 호출이 되면 문자열 출력 후 자동으로 개행(줄 바꿈)이 이뤄지지만, fputs함수가 호출되면 문자열 출력 후 자동으로 개행이 이뤄지지 않아 printf("\n"); 와 같이 별도의 개행 작업을 거쳐야 한다.


<추가적으로..>

문자열을 문자 배열에 저장하는 형식만 사용을 해와서 처음 char * str = "Simple String";의 코드를 보고 어떻게 쓰여야 할지는 알지만 조금 더 알아보고 싶어서 정리를 해 보았다.

 

처음에 생각했던 것은 char * str = "Simple String"; 의 코드에서 "Simple String"는 문자열이고, 문자열은 그 자체로 주소 값을 가지고 있으므로 이렇게 문자열을 적어 넣으면, 문자열 즉 배열의 주소 값이 전달되고 있으며,

그러면 str은 이 문자열의 주솟값을 의미한다. 그리고 * str은 "Simple String"의 문자열을 의미할 것이라고 생각했었다.

 

위 생각에 보충을 하자면, 문자열이 메모리 공간에 먼저 저장이 되고, 메모리 주소 값이 반환이 된다. 그렇게 되면 str은 이 문자열에 대한 주솟값을 저장하게 되는 것은 맞다. str이 해당 문자열을 가리키는 것이다. 앞의 생각에서 부족하지만 그래도 틀린 생각이 아니었다면 * str은 "Simple String"의 문자열을 의미할 것이라고 생각한 것은 틀린 생각이었다고 할 수 있다. 

 

처음에는 틀린 이유를 아래와 같이 생각해 보았었다.

*str과 같은 형식은 int형에서는 *str = 값 ; 과 같은 형태로 사용이 되지만 문자열 포인터에서는 사용이 되지 않는 잘못된 문장이다.

int형에서는 *pnum은 포인터 변수 pnum이 가리키는 변수 num을 의미한다. 즉 가리키는 값이 정확히 하나이다.

그런데 배열이나 문자열에서는 가리키는 값이 정확히 하나가 아니다. 그러므로 *str과 같은 문장이 작성되지 않는다라고 생각했고, 배열의 값 인덱스를 통해 값을 출력해야 한다고 생각을 했었다. 그러나 위 생각은 옳지 않고 아래와 같이 정리를 해보았다.

 

 

<틀린 이유 정리>

#include<stdio.h>
int main(void)
{
	char arr[] = "my hobby";
	printf("%c\n", *arr);
	printf("%s", arr);
	return 0;
}

변수 형태의 문자열이고, 즉 흔히 아는 문자열이다. *arr의 값으로 문자열의 첫 번째 값인 문자 m 이 출력이 된다. 

 

#include<stdio.h>
int main(void)
{
	char * str = "you hobby";
	printf("%c\n", *str);
	printf("%s", str);
	return 0;
}

상수 형태의 문자열이고, *str의 출력 값으로 y가 출력이 된다. 즉 문자열에서 *str과 같은 형태가 쓰이지 않는 것이 아니라

*str의 값은 문자열 str이 가리키는 배열의 첫 번째 요소의 값을 의미한다는 것이다.

즉 위 예제 코드에서 * str이 의미하는 것은 "Simple String"의 문자열이 아니라 문자 S라는 것이다.


 

<문자열 사용의 잘못된 예제>

#include<stdio.h>
int main(void)
{
	char str = "hi";
	printf("%s", str);
	return 0;
}

C언어는 문자를 저장하는 자료형인 char형이 있지만 문자열을 저장하는 자료형은 없다.

그래서 위의 코드와 같이 char에 문자열을 저장해서는 안된다.

 

그렇다면 문자열은 어떻게 저장을 해야 할까? 문자열은 char 포인터 형식으로 사용을 해주어야 한다.

char * str = "Simple String"; 의 위 예제에 있는 코드와 같이 말이다.

 

 

<잘못된 코드>

#include<stdio.h>
int main(void)
{
	char *str = "hi";
	*str = "hello";
	printf("%s", str);
	return 0;
}

 *str = "hello"; 이와 같은 문장은 잘못되었다. 가리키는 대상을 변경하려는 문장을 입력하고자 한다면 다음과 같이 문장을 작성하여야 한다.  str = "hello"; 와 같이 포인터 변수 str을 통해 가리키는 대상을 변경해 주는 것이다.

*str이 의미하는 값은 문자열의 첫 번째 문자인 h이다. 즉 이 문자를 문자열로 바꾼다?라고 생각하면 이상하다고 생각할 수 있을 것 같다.

 

 

<int 형 포인터 예제>

#include<stdio.h>
int main(void)
{
	int num = 5;
	int *str = &num;
	*str = 6;
	printf("%d", *str);
	return 0;
}

printf("% d", str);  의 코드에서 str을 출력한다면 str은 num의 주솟값을 가리키므로 주솟값을 출력한다는 의미가 되고, 서식 문자는 % p를 사용해주는 것이 옳다.


<참고>

 

C 언어 코딩 도장: 39.1 문자와 문자열 포인터 알아보기

문자열은 char 포인터 형식으로 사용합니다. char *변수이름 = "문자열"; 다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요. string_pointer.c #include int main() { char c1 = 'a'; // 변수에 문자 'a' 저장

dojang.io

"이 문자열 리터럴이 있는 메모리 주소는 읽기 전용이므로 다른 문자열을 덮어쓸 수는 없습니다."라는 문장이 있는데, 가리키는 대상을 바꾸지 못한다는 것이 아니라, 가리키고 있는 문자열의 내용을 변경하지 못한다 라는 뜻으로 이해하면 될 것 같다. 즉 상수 형태의 문자열 이기 때문이다. 

 

<참고 2>

https://keep-going99.tistory.com/136