https://www.notion.so/12-11bd2c198d5980ebb343f42f90493edb?pvs=4
char* get_apple(){
char* p = "apple";
return p;
}
int main(){
char* str = get_apple();
printf("%s\n", str);
return 0;
}
get_apple 함수
char* get_apple() {
char* p = "apple";
return p;
}
"apple"의 주소를 가리키는 포인터 p를 반환합니다."apple"의 시작 주소를 p가 가리키고 있습니다.p)의 값을 반환합니다.main 함수
int main() {
char* str = get_apple();
printf("%s\n", str);
return 0;
}
get_apple 함수가 반환한 문자열 리터럴의 주소를 str에 저장합니다.printf("%s\n", str);는 str이 가리키는 문자열 "apple"을 출력합니다."apple"이 출력됩니다.#define MAX 15
int main() {
char ch, str[MAX];
int i;
printf("Enter a sentence to reverse\n");
for(i = 0; (ch = getchar()) != '\n'; i++)
str[i] = ch;
str[i] = 0;
for(--i; i>=0; i--)
putchar(str[i]);
return 0;
}
main 함수char ch, str[MAX];
int i;
char ch: 한 번에 한 문자를 저장하기 위한 변수입니다.char str[MAX]: 최대 15개의 문자를 저장할 수 있는 배열입니다. 입력받은 문자열이 여기에 저장됩니다.int i: 배열의 인덱스를 관리하는 변수입니다.for 루프: 문자열 입력for(i = 0; (ch = getchar()) != '\n'; i++)
str[i] = ch;
str[i] = 0;
getchar()를 사용하여 한 문자씩 입력받습니다.str의 각 위치에 저장합니다.'\n')가 아니면 계속 입력을 받습니다.\0)를 추가하여 문자열의 끝을 표시합니다.MAX로 제한되어 있어 입력 길이가 14자를 초과하면 버퍼 오버플로우 위험이 있습니다.for 루프: 문자열 역순 출력for(--i; i >= 0; i--)
putchar(str[i]);
i: 첫 번째 루프 종료 후 i는 문자열 끝을 가리키므로 1 감소시켜 마지막 유효 문자를 가리키도록 합니다.i >= 0: 배열의 첫 번째 문자가 포함되도록 조건 설정.putchar(str[i]): 배열을 역순으로 순회하며 각 문자를 출력합니다.#define MAXCHAR 20
#include<ctype.h> // for islower, toupper
char* read_line(){//입력문장을 text 배열에 넣고 시작 주소를 돌려준다.
char ch;
int i;
static char text[MAXCHAR];
//함수를 빠져나가도 사라지지 않게 하기 위해 정적 변수로 선언
printf("Enter a sentence.\n");
for(i=0; (ch = getchar()) != '\n'; i++){
text[i] = ch;
}
text[i] = '\0'; //마지막 NULL로 설정할려고. text[i]는 NULL 가리키겠네.
return text;
}
int main(){
int i;
char* p = read_line();
for(i = 0; p[i] != 0; i++){
if(islower(p[i]))
p[i] = toupper(p[i]);
putchar(p[i]); // 조건에 상관없이 p[i]출력.
}
printf("\n");
return 0;
}
read_line 함수
textstatic char text[MAXCHAR]는 정적 변수로 선언되었으므로 함수가 종료되더라도 메모리에서 사라지지 않습니다.text의 시작 주소를 안전하게 반환할 수 있습니다.for 루프에서 getchar()를 사용해 한 문자씩 입력을 읽습니다.text의 각 위치에 저장합니다.'\n')를 만나면 루프를 종료합니다.text[i] = '\0';을 통해 문자열의 끝을 나타내는 널 문자(\0)를 추가합니다.text의 시작 주소를 반환합니다.main 함수에서 입력 문자열에 접근할 수 있습니다.main 함수
read_line 함수를 호출하여 문자열을 입력받습니다.p에 저장합니다.for 루프: 문자열 처리for(i = 0; p[i] != 0; i++):p[i]가 널 문자(\0)가 아닐 때까지 루프가 반복됩니다.islower(p[i]): p[i]가 소문자인지 확인합니다(C 라이브러리 함수).toupper(p[i]): 소문자를 대문자로 변환합니다(C 라이브러리 함수).p[i]에 다시 저장합니다.putchar(p[i]): 현재 문자를 출력합니다.printf("\n");로 줄바꿈을 추가합니다.text가 정적 변수(static)로 선언되었으므로 함수 종료 후에도 값을 유지합니다.text는 정적으로 선언되었으므로 안전하게 수정 가능합니다.#include <string.h>
void swap(char*, char*);
void permute(char*, int, int);
int main() {
char str[] = "abc";
printf("%d\n", strlen(str));
permute(str, 0, strlen(str)-1); // 1
return 0;
}
void swap(char* x, char* y){
char temp;
temp = *x;
*x = *y;
*y = temp;
}
void permute(char* s, int left, int right){ // 2
int i;
if(left == right) //3
printf("%s\n", s);
else{
for(i = left; i<=right; i++){ //4
swap(s+left, s+i); //5
permute(s, left, right); // 6 -> 재귀로 순열 구함
swap(s+left, s+i); // 7 백트래킹
}
}
}
int main() {
char str[128];
printf("Enter: \n");
scanf("%[A-Z]s", str); //대문자 A-Z 사이 문자만 읽음
printf("String before lower case: %s\n", str);
while(getchar() != '\n');
printf("Enter: \n");
scanf("%[^e]s",str); // 첫 e를 만나기 전까지 읽음
printf("String before e is %s\n", str);
while(getchar() != '\n');
printf("Enter with space: \n");
scanf("%[^\n]s",str); // \n만나기 전까지 읽음 이게 빈칸이 아님.
printf("you entered %s\n", str);
while(getchar() != '\n');
printf("Enter with space: \n");
gets(str); // 한줄 읽기 함수. Enter누르기 전까지 모든 문자 읽음.
printf("you entered %s\n", str);
return 0;
}

int main() {
char str[10];
printf("Enter a string: ");
printf("\n");
gets(str);
puts(str);
do{
printf("Enter another string: \n");
gets(str);
puts(str);
}while(*str != 0);
printf("Enter a very Long string.\n");
gets(str);
printf("you entered, \n");
puts(str);
return 0;
}

#include <string.h>
int main() {
char text[10];
printf("Enter a text \n");
fgets(text, sizeof(text), stdin);
printf("you entered text: %s", text);
printf(" It's length is %d\n", strlen(text));
//apple 입력시 length가 5여야 되는데 6임 null때매
text[strlen(text) - 1] = '\0';
printf("you entered text: %s\n", text);
printf(" It's length is %d\n", strlen(text));
//이렇게 해야 5가 나온다
return 0;
}

int main() {
char first[6], last[6];
printf("Enter first name.\n");
fgets(first, sizeof(first), stdin);
//while(getchar() != '\n');
printf("Enter last name.\n");
fgets(last, sizeof(last), stdin);
printf("Full name: \n");
puts(first);
puts(last);
return 0;
}

1. strlen
int main() {
char *str1 = "pine", *str2 = "apple";
if(strlen(str1) - strlen(str2) >= 0) //unsigned int기 때문에 절댓값
printf("yes\n");
else
printf("no\n");
if(strlen(str1) > strlen(str2))
printf("yes\n");
else
printf("no\n");
if(((int)strlen(str1) - (int)strlen(str2)) >= 0)
printf("yes\n");
else
printf("no\n");
return 0;
}
출력결과: yes, no, no
2. strcat

문자열을 이어 붙이는 함수.
src가 가리키는 문자열을 dest에 이어 붙인 다음에 dest 리턴.
3. strcmp


4. strcpy

#include <string.h>
int main() {
char str1[30], str2[10];
printf("Enter a string: \n");
gets(str1);
printf("Enter a string: \n");
gets(str2);
printf("strlen(str1) = %d\n", strlen(str1));
printf("strlen(str2) = %d\n", strlen(str2));
if(strcmp(str1,str2) ==0)
printf("%s and %s are equal\n", str1, str2);
else if(strcmp(str1,str2) < 0)
printf("%s is smaller than %s\n", str1, str2);
else
printf("%s is bigger than %s\n", str1, str2);
printf("Before strcpy\n str1 = %s, str2 = %s\n", str1, str2);
strcpy(str1, str2);
printf("After strcpy\n str1 = %s, str2 = %s\n", str1, str2);
printf("Before strcat\n str1 = %s, str2 = %s\n", str1, str2);
strcpy(str1, str2);
printf("After strcat\n str1 = %s, str2 = %s\n", str1, str2);
printf("%s \n", strcat(str1, "OMG!"));
return 0;
}
실행결과:
Enter a string:
lemon
Enter a string:
tree
strlen(str1) = 5
strlen(str2) = 4
lemon is smaller than tree
Before strcpy
str1 = lemon, str2 = tree
After strcpy
str1 = tree, str2 = tree
Before strcat
str1 = tree, str2 = tree
After strcat
str1 = tree, str2 = tree
treeOMG!
//직접 구현한 strlen() 함수
int my_strlen(const char *str){
int i;
for(i=0; str[i] != '\0'; i++);
return i;
}
int main(){
char text[30];
printf("Enter a text \n");
gets(text);
printf("Length of text is %d \n", my_strlen(text));
return 0;
}
//재귀 호출로 strlen() 구현
int recursive_strlen(const char *str){
if(*str == '\0')
return 0;
else
return (1+recursive_strlen(++str));
}
int main(){
char text[30];
printf("Enter a string: \n");
gets(text);
printf("Lent: %d\n",recursive_strlen(text));
return 0;
}
//직접 구현한 strcpy() 함수
char* my_strcpy(char *dest, char *src) {
int i = 0;
while((dest[i] = src[i]) != '\0')
i++;
return dest;
}
int main(){
char dest[30], src[10];
printf("Enter desination string\n");
gets(dest);
printf("Enter source string\n");
gets(src);
printf("On strcpy(dest, src), dest became %s\n", my_strcpy(dest, src));
return 0;
}
src에서 dest로 복사하므로 src 앞에만 const 지정자를 붙임.
// strcpy() 포인터 버전
char* mystrcpy(char *dest, const char *src){
char* backup = dest;
while(*src != '\0'){
*dest = *src;
dest++;
src++;
}
*dest = '\0';
return backup;
}
int main(){
char dest[30], src[10];
printf("Enter a string: \n");
gets(dest);
printf("Enter another string: \n");
gets(src);
printf("strcpy(dest, src) -> %s \n", mystrcpy(dest, src));
return 0;
}
// strchr() , strstr()

int main() {
char *here, *there;
char text[] = "This is first. This is second. This is third.";
const char ch='.';
here = strchr(text, ch); //text문자열에서 처음 나타나는 마침표를 가리킨다.
printf("Text after the first period is, %s\n", (here+2));
//마침표 뒤에 빈칸이 있으므로 here+2는 다음 문장의 첫 글자.
strcpy(text, "It is a right answer.");
there = strstr(text, "right"); //right의 첫번째 문자열 r
strncpy(there, "wrong", 5); //n개의 문자만 strcpy하라.
//즉 there가 가리키는 위치에 wrong이라는 문자열을 복사. 문자 5개만!
puts(text);
return 0;
}
int main() {
char str[100];
char* name = "Lee eun";
int age = 19;
double weight = 58.5;
char *first = "First line of a long string. ";
char *second = "Second line of a long string. ";
sprintf(str, "Name: %s, Age: %d, Weight: %lf.", name, age, weight);
puts(str);
sprintf(str, "%s %s", first, second);
puts(str);
return 0;
}
sprintf는 pirntf함수의 출력을 화면이 아니라 배열로 내보낸다.
#include <string.h>
int main() {
char str[] = "J.Park Seoul 010-2222-3456";
char *p = strtok(str, " ");
while(p != NULL){
printf("%s\n", p);
p = strtok(NULL, " ");
}
return 0;
}
실행결과
J.Park
Seoul
010-2222-3456
strtok(string token) 함수는 문자열을 토큰 단위로 분리하기 위한 것.
strtok함수를 호출하면 처음 빈칸을 만나기 전까지의 토큰만 분리하여 그 문자열의 시작주소를 돌려준다.

유니코드 표준은 한글을 2바이트로 나타낸다.

int main() {
char str[4];
printf("Enter a string: \n");
scanf("%s", str);
printf("After scanf, str became %s\n\n", str);
return 0;
}
scanf 도 버퍼 오버플로우에 노출되어 있다. str[4]라고 선언 했으므로 ‘\0’을 제외하면 세자리만 남음.
길이가 3을 넘는 문자를 입력하면 오버플로우가 일어남.
→ 하지만 결과는 yellow를 입력하면 yellow가 나옴.
→ 이게 버퍼오버플로우가 발생한거다.
int main() {
char str[4];
printf("Enter a string: \n");
scanf_s("%s", str, sizeof(str));
printf("After scanf_s str became %s\n", str);
return 0;
}
scanf_s를 쓰면 red를 입력시 red를 출력하지만, blue를 입력시 출력하지 않는다.
즉, 버퍼 오버플로우를 방지하기 위한 함수가 scanf_s다.
위에서 사용한 strncpy( ) 또한 버퍼 오버플로우 방지하기 위한 함수.
왜? n개 만큼만 복사하라는 뜻.
int main() {
char dest[9];
char* src = "mju.ac.kr";
char str[9];
strncpy(dest,src, sizeof(dest));
printf("%s\n", strcpy(str,dest));
return 0;
}
오류가 있다.
dest 길이는 9지만, src의 길이는 null까지 포함하면 10이다.
따라서 strncpy함수를 쓰면 dest에 null이 들어가지 않는다.
이 경우 문제가 발생한다.
char* safe_strcpy(char*, const char*);
int main() {
char source[100];
char* destination = NULL; //문자열 복사 결과를 저장할 포인터
printf("Enter source string: \n");
gets(source);
destination = safe_strcpy(destination, source);
printf("After safe string copy, detination points to\n");
puts(destination);
free(destination);
return 0;
}
char* safe_strcpy(char *dest, const char *src) {
char* backup;
dest = (char*)malloc(sizeof(char) * (strlen(src)+1));
//malloc을 통해 src 문자열의 크기(strlen(src))에 맞는 메모리 할당
// +1은 null 문자를 위한 공간임.
if(dest == NULL){
printf("No more memory.\n");
exit(1);
}
backup = dest; // 복사된 문자열의 시작 주소를 저장
while(*dest++ = *src++);
return backup;
}
while문은
src에서 한 문자를 읽어 dest에 복사한 뒤 포인터를 각각 1씩 증가시킴.
null 만나면 루프 종료.
source: "Hello, World!"safe_strcpy 호출:src는 "Hello, World!".malloc으로 14바이트(13 + 1)의 메모리를 할당."Hello, World!"를 동적 메모리로 복사."Hello, World!" 출력.free(destination)로 할당된 메모리를 해제.char* my_strcpy(char*, const char*);
int main(){
char source[30], *destination = NULL;
printf("Enter the string: ");
gets(source);
destination = my_strcpy(source, source);
printf("After copying the string: %s\n", destination);
puts(destination);
free(destination);
return 0;
}
char* my_strcpy(char* dest, const char* src){
dest = (char*)malloc(sizeof(char) * strlen(src)+1));
if(dest == NULL){
printf("No more memory.\n");
exit(1);
}
memset(dest, 0, sizeof(char) * (strlen(src)+1));
memcpy(dest, src, sizeof(char) * (strlen(src)+1));
return dest;
}

#define FRIENDS 3
#define MAX 10
#include <string.h>
void swap(char *p, char *q) {
char temp[MAX];
strcpy(temp,p);
strcpy(p,q);
strcpy(q,temp);
}
void bubble_sort(char arr[FRIENDS][MAX]) {
int pass, current, sorted = 0;
for(pass = 1;(pass<FRIENDS) && (!sorted) ;pass++){
sorted = 1;
for(current = 0; current <(FRIENDS - pass);current++){
if(strcmp(arr[current], arr[current+1]) > 0)
swap(arr[current], arr[current+1]);
}
}
}
void print_array(char arr[FRIENDS][MAX]) {
int i;
printf("\n");
for(i=0; i< FRIENDS; i++)
puts(arr[i]);
}
int main(){
char name[MAX];
char list[FRIENDS][MAX];
int i;
for(i=0; i<FRIENDS; i++){
printf("Enter name: \n");
gets(name);
strcpy(list[i], name);
}
bubble_sort(list);
print_array(list);
return 0;
}


#define MAX 10
#include <stdio.h>
#include <string.h>
int main() {
char wish_list[MAX][100];
char temp[100];
int i = 0, j;
while (1) {
printf("Enter your wishes.\n");
gets(temp);
if (strcmp(temp, "quit") == 0)
break;
strcpy(wish_list[i], temp);
i++;
}
for (j = 0; j < i; j++)
puts(wish_list[i]);
return 0;
}
// example_12-31.c
#define MAX 10
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char * wish_list[MAX];
char temp[100];
int i = 0, j;
while (1) {
printf("Enter your wishes.\n");
gets(temp);
if (strcmp(temp, "quit") == 0)
break;
wish_list[i] = (char*)malloc(sizeof(char)*(strlen(temp)+1));
if (wish_list[i] == NULL) {
fprintf(stderr, "No more memory.\n");
exit(1);
}
strcpy(wish_list[i], temp);
i++;
}
for (j = 0; j < i; j++)
puts(wish_list[j]);
for (j = 0; j < i; j++) {
free(wish_list[j]);
wish_list[j] = NULL;
}
return 0;
}
