[TIL]20210926
C
문자열 상수 관련.
int main(void){
char *dessert= "apple"; //문자열을 주소이다!!. 주소에 접근한 후 상자를 열어 값을 수정해야하지, 주소 값을 apple, banana로 바꿀려니까 안되지.
printf("%s %p\n",dessert,dessert);
dessert="banana";
printf("%s %p\n",dessert,dessert); // 문자열은 상수. 포인터로 주소에 접근해서 상자 내부의 값을 변경하는 것이 아니라, 다른 상자 주소를 가리키도록 만드는 것.
}
int main(void){
char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
scanf("%s",str); // scanf();는 공백이 없는 연속된 문자열을 입력받음.
printf("%s\n",str);
scanf("%s",str);
printf("%s\n",str);
// "apple jam" 입력하면
// apple
// jam
// 이렇게 출력됨.
}
int main(void){
char *dessert= "apple"; //문자열을 주소이다!!. 주소에 접근한 후 상자를 열어 값을 수정해야하지, 주소 값을 apple, banana로 바꿀려니까 안되지.
printf("%s %p\n",dessert,dessert);
dessert="banana";
printf("%s %p\n",dessert,dessert); // 문자열은 상수. 포인터로 주소에 접근해서 상자 내부의 값을 변경하는 것이 아니라, 다른 상자 주소를 가리키도록 만드는 것.
}
int main(void){
char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
scanf("%s",str); // scanf();는 공백이 없는 연속된 문자열을 입력받음.
printf("%s\n",str);
scanf("%s",str);
printf("%s\n",str);
// "apple jam" 입력하면
// apple
// jam
// 이렇게 출력됨.
}
apple jam
을 입력하면 버퍼에 두 단어가 임시저장되고, scanf에서는 공백을 기준으로 끊기때문에 apple
만을 가져간다. 그 후, 다시 scanf에서 jam
을 가져간다.
gets
공백이나 탭 문자도 입력이 필요할 경우 gets()
을 이용한다.
int main(void){
char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
gets(str);
printf("%s\n",str);
}
apple jam
을 입력하면 그대로 출력된다.
scanf는 스페이스바, 탭, 엔터 입력값을
/0
으로 변환하고, gets는 엔터 입력값만/0
으로 바꾸고 나머지는 다 본래의 값을 보관한다.
fgets
앞의 scanf, gets는 버퍼에서 가져오는 문자열의 크기와 선언한 배열의 크기를 비교하지 않기때문에, 입력받다가 할당되지 않은 메모리 공간을 침범하는 문제가 발생할 수 있다. 이를 예방하기위해 fgets를 사용한다.
fgets(str, sizeof(str), stdin);
배열명, 배열의 크기, 표준 입력 순으로 작성한다.
배열 크기는 -1을 하지 않아도 알아서 마지막 한칸은 \0
으로 생각하고 입력을 받아준다.
그리고 마지막의 표준 입력은, scanf와 gets는 기본적으로 표준입력을 사용하지만, fgets는 입력 버퍼를 선택할 수 있다. 다른 것과 마찬가지로 표준입력을 사용할 것이기에 stdin으로 사용.
fgets는 엔터 입력값인 \n
을 \0
으로 바꾸는 앞의 함수들과 다르게 개행문자까지 저장하고 마지막에 널 문자를 붙인다. 그렇기 때문에 밑의 경우처럼 %s뒤에 문자를 더 작성하면 개행 된 후 "입니다"가 출력된다. 이를 예방하기위해 str[strlen(str)-1]='\n';
을 이용한다. strlen(str)의 자리에는 \0
이 있고 그 한 칸앞에 \n
이 있기에 -1을 붙여준다.
int main(void){
char str[80]; //char* 을 이용해 칸 수 제한을 없애든지, str[80]등으로 칸 수 제한을 두던지.
fgets(str,sizeof(str),stdin);
str[strlen(str)-1]='\n';
printf("%s입니다.",str);
}
scanf, getchar | gets, fgets의 버퍼 공유 문제와 해결방안.
scanf() 함수는 \n(줄바꿈문자)를 가져오지 않고, 마지막에 \0(널문자)를 붙인다.
getchar 함수 또한 scanf와 비슷할듯?( 얘는 잘 모르겠음)
gets() 함수는 \n(줄바꿈문자)까지 가져오고, \n을 \0으로 대체 한다.
fgets() 함수는 \n(줄바꿈문자)까지 가져오고, 추가적으로 \0을 붙인다.
즉, scanf와 getchar는 버퍼에 \n
을 남긴다. 개행문자 전까지의 값을 메모리에 가져온 후에 \0
을 붙인다. gets나 fgets는 \n
까지 가져온다.
이 차이로 인해 문제가 생긴다.
scanf나 getchar로 문자를 입력받으면 버퍼에 \n
이 남아서 다음번에 버퍼에서 값을 가져오려할때 이 \n
만 입력받고 함수를 끝낸다.
이를 해결하기 위해
1.
getchar();
2.
scanf("%*c");
3.
fgetc(stdin);
함수를 이용.
위 코드들은 작동방식에서 조금의 차이는 있지만, 결론적으로 버퍼의 맨 앞 한칸을 가져와서 버린다.
puts, fputs
put(str); // 자동 줄 바꿈.
put(str,stdout); // 줄 바꾸지 않음.
strcat, strncat
문자열을 뒤에 이어 붙인다.
char str[80]= "straw";
strcat(str, "berry"); --> strawberry
strncat(str, "piece" ,3); --> strawpie
주의사항, 사용할 배열은 초기화 되있어야함. 이어붙일때 널 문자 위치를 기준으로 하기 때문.
strcmp, strncmp
문자열 비교.
strcmp(str1, str2);
str1과 str2가 똑같이 대 or 소 문자일 경우만 정확한 비교가 됨.
각 자리 수마다 비교해서 str1이 str2보다 사전에 나중에 나오면(아스키 코드값이 크면) 1을 반환, 그 반대면 -1을 반환. 같으면 0을 반환한다.
strcpy 함수 만들어보기.
char *my_strcpy(char *pd, char *ps);
int main(void){
char str[80]="starwberry";
printf("before : %s\n", str);
my_strcpy(str,"apple");
printf("after : %s\n", str);
return 0;
}
char *my_strcpy(char *pd, char *ps){
char *po = pd; //예전 파이썬 알고리즘 할때 공부한 내용. pd는 주소값이 계속 변하기때문에, 초기 메모리 위치를 기억할 친구가 하나 필요.
while(*ps != '\0'){
*pd=*ps; //배열이 아니기 때문에 문자열 상수가 아님. 그럼으로 내부수정이 가능. *pd로 주소의 상자를 열고 *ps로 다른 상자의 내용물을 그대로 복사.
pd++;
ps++;
}
*pd='\0';
return po;
}
Author And Source
이 문제에 관하여([TIL]20210926), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kid_chang/TIL20210926저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)