1. scanf_s의 사용법
1) scanf_s는 크기를 지정한 byte를 저장시킨다.
scanf_s("%s", s1, 10);
위 방식과 같이 scanf와 동일하지만 3번 째 매개변수가 있다. 이것은 기존의 scanf의 단점을 보완한 것으로 제한된 크기를 리턴하는 것이 scanf_s이다. 3번째 매개변수는 byte단위의 크기 값인데 10byte의 크기를 무조건 반환한다.
사용자가 char s1[100]의 값 s1에 문자열을 저장할건데
※ 9자리의 문자열 + '\0'를 반환한다.
경우1)
10보다 작은 5byte 문자열을 입력하면 5byte+4개의 null+'\0' 이렇게 총 10자리를 반환한다.
경우2)
9보다 큰 즉 10자리 이상을 입력하면 그 입력은 무시된다.
2) scanf_s는 %s와 %s가 아닌 경우에서 사용 법이 나뉜다.
int main() {
char s1[10];
scanf_s("%s", s1, sizeof(10));
int a;
scanf_s("%d", &a);
}
%s로 사용하는 경우 세 번째 인자의 값이 꼭 있어야한다.
%s가 아닌 경우는 하나의 단위(int 1개, char 1개 등등)를 입력 받는 경우로 세 번째 인자의 값을 적어도되고 안적어도된다.
2. char* s와 char a[10]의 차이점
char* s1 = NULL;
scanf_s("%s", s1, sizeof(10));
/*error*/
s1은 4byte 메모리 공간이다. 이 공간에는 char형의 1byte 문자열의 메모리 공간의 주소를 담을 수 있다.
char *s1 = "Hello";
위와 같이 배열을 선언해도 된다.
이것은 "Hello"라는 6byte("Hello + '\0')문자열이 메모리 공간에 생기는데 s1은 그 메모리 공간의 처음 주소를 가진다.
위 예시코드가 실제로 동작안되는 이유는 우선 scanf_s는 사용자가 몇 자리를 입력하던 9byte 이하이기만하면 9byte를 반환하는데, s1은 4byte 메모리 공간인데 이 공간에 문자열을 넣을 수 없다.
아래 코드와 같이 바꾸거나 char[] 공간을 동적할당하여 그 공간을 s1이 가리키도록 한 뒤 그 공간에 사용자로부터 scanf를 하면 된다.
char s1[10];
scanf_s("%s", s1, sizeof(s1));
/*correct*/
이렇게 코드를 수정해야한다.
3. 동적 할당
int main() {
int size;
printf("크기 입력 >>");
scanf_s("%d", &size);
char* s1 = (char*)malloc(sizeof(char) * size);
printf("%d 자리 문자열 입력>>", size-1);
scanf_s("%s", s1, sizeof(char) * size);
printf("%s", s1);
free(s1);
}
int main() {
char* s1 = malloc(sizeof(char) * 10); // char 10개 크기만큼 동적 메모리 할당
printf("문자열을 입력하세요: ");
scanf_s("%s", s1, sizeof(char) * 10); // 표준 입력을 받아서 메모리가 할당된 문자열 포인터에 저장
printf("%s\n", s1); // 문자열의 내용을 출력
free(s1); // 동적 메모리 해제
}
두 번째 코드를 분석하면
s1은 동적할당 전에 char 1byte 크기의 메모리 공간 주소를 가질 수 있는 변수이다. (그 이상도 그 이하도 아님)
동적할당을 통해 sizeof(char)*10=10byte 크기를 할당받았다.
따라서 동적할당의 결과로 s1은 10byte의 char 공간을 가졌고 첫 주소를 s1이 가지고 있는 것이 된다.
s1은 힙 영역에 메모리 공간으로 10byte를 가지므로 scanf_s가 가능해진다.
s1에도 역시 9byte 문자열이 들어가고 끝 1byte는 '\0'이다.
4. 의문
int main() {
char* s1 = (char*)malloc(sizeof(char) * 10);
printf("%d\n", sizeof(s1)); // 4
printf("%d\n", strlen(s1)); // 14
char* s2 = NULL;
printf("%d\n", sizeof(s2)); // 4
char* s3 = "abcde";
printf("%d\n", sizeof(s3)); // 4
printf("%d\n", strlen(s3)); // 5
char s4[5] = "abcd";
printf("%s\n", s4); //abcd
printf("%d\n", sizeof(s4)); //5
printf("%d\n", strlen(s4)); //4
}
파란 글은 모르는걸 해결한 글임.
빨간 글은 왜그런지 모르는 거임
● s4와 같이 배열로 문자열을 지정할때 크기는 5이지만 실제로 4byte만 작성되야함 끝에 1byte는 '\0'이 들어감
● char* 타입으로 지정된 변수를 sizeof하면 값이 있던 말던 무조건 4가나옴 => 왜???
해결=> s1에는 char 타입 하나를 저장할 수 있는 공간의 "메모리 주소"를 가지는데 메모리 주소는 32bit 시스템에서 4byte이기 때문임
● strlen(s1)은 왜 10이 아니라 14가 나오지? 왜??
해결=> strlen은 문자열의 길이를 구하는 함수이고 null(''\0")은 포함안함.
sizeof는 메모리의 크기를 바이트 단위로 계산한다.
s1이 동적할당은 받았지만 문자열을 가지지 않으므로 애초에 strlen을 사용하면 안됨!
s1에 동적할당을 받았으니 문자열을 입력 한 뒤 strlen을 하면 끝에 null이 들어가긴 하지만 null 빼고 길이를 정상적으로 읽음 아래는 문제점 해결 코드임
//solution코드
int main() {
char* s1 = (char*)malloc(sizeof(char) * 10);
s1 = "abcdefg";
printf("%d\n", strlen(s1)); // 7
printf("%d\n", sizeof(s1)); // 4
char* s2= NULL;
s2 = "abcd";
printf("%d\n", strlen(s2)); // 7
}
● s1은 동적 할당으로 10byte의 크기를 할당 받았다=> 저장 가능한 문자열은 9byte이다.
● 실제로 s1은 10byte를 할당 받아 9byte가 들어갈 수 있지만 scanf_s의 3번째 매개변수를 충분히 크게주어 10byte이상을 입력하면 s1에 10byte 이상의 크기 모두가 다 들어감.
아니 동적할당으로 10byte만 할당받았는데 왜 10byte 이상이 더 들어감? 알아서 크기 늘어나나??
int main() {
char* s1 = (char*) malloc(10);
s1 = "abcde";
printf("%d\n", strlen(s1)) // 5
char* s1 = (char*) malloc(3);
s1 = "abcde";
printf("%d\n", strlen(s1)) // 5
}
char *s1으로 동적할당으로 heap영역에 10 byte 길이의 메모리 주소를 할당 받았지만 이후 s1 = "abcde"이렇게 선언한 것은 기존에 s1이 가지고 있던 heap영역에 동적 메모리 주소를 버리고 문자열이 저장된 메모리공간의 시작 주소를 가지는 것임 . 그래서 strlen은 문자열의 길이를 나타내므로 위와 같은 결과가 나온는 것임.
'잡지식' 카테고리의 다른 글
c언어 배열 끝에 '\0' (0) | 2021.12.12 |
---|