새 문자열 값을 올바르게 할당하려면 어떻게 해야 합니까?
저는 C의 이 사소한 문제를 가장 깔끔하고 안전한 방법으로 해결하는 방법을 이해하려고 합니다.예를 들어 보겠습니다.
#include <stdio.h>
int main(int argc, char *argv[])
{
typedef struct
{
char name[20];
char surname[20];
int unsigned age;
} person;
// Here I can pass strings as values...how does it work?
person p = {"John", "Doe", 30};
printf("Name: %s; Age: %d\n", p.name, p.age);
// This works as expected...
p.age = 25;
//...but the same approach doesn't work with a string
p.name = "Jane";
printf("Name: %s; Age: %d\n", p.name, p.age);
return 1;
}
컴파일러 오류:
main.c: 함수 'main'에서: main.c:18: 오류: 유형 'char *'에서 유형 'char[20]'에 할당할 때 호환되지 않는 유형
C(C++가 아님)에는 String 타입이 없고 대신 C++의 배열을 사용하는 것으로 알고 있습니다.char
s, 그래서 이것을 하는 또 다른 방법은 예시 구조를 변경하여 포인터를 유지하는 것입니다.char
s:
#include <stdio.h>
int main(int argc, char *argv[])
{
typedef struct
{
char *name;
char *surname;
int unsigned age;
} person;
person p = {"John", "Doe", 30};
printf("Name: %s; Age: %d\n", p.name, p.age);
p.age = 25;
p.name = "Jane";
printf("Name: %s; Age: %d\n", p.name, p.age);
return 1;
}
이것은 예상대로 됩니다만, 더 좋은 방법이 없을까요?
첫 번째 예는 배열에 값을 할당할 수 없기 때문에 작동하지 않습니다.배열은 이 점에서 const pointer와 같이 동작합니다.다만, 새로운 값을 어레이에 카피할 수 있습니다.
strcpy(p.name, "Jane");
문자 배열은 문자열의 최대 크기를 미리 알고 있는 경우 사용할 수 있습니다.예를 들어 첫 번째 예에서는 이름이 19자 안에 들어가는 것을 100% 확신할 수 있습니다(종료 0 값을 저장하기 위해서는 항상 한 문자가 필요하므로 20자가 아닙니다).
반대로 가능한 최대 문자열 크기를 모르거나 메모리 사용을 최적화하려면 포인터가 더 좋습니다. 예를 들어 "John" 이름에 512자를 예약하지 마십시오.단, 포인터를 사용하면 포인터가 가리키는 버퍼를 동적으로 할당하고 더 이상 필요하지 않을 때 해방하여 메모리 누수를 방지해야 합니다.
업데이트: 동적으로 할당된 버퍼의 예(두 번째 예시의 구조 정의를 사용):
char* firstName = "Johnnie";
char* surname = "B. Goode";
person p;
p.name = malloc(strlen(firstName) + 1);
p.surname = malloc(strlen(surname) + 1);
p.age = 25;
strcpy(p.name, firstName);
strcpy(p.surname, surname);
printf("Name: %s; Age: %d\n",p.name,p.age);
free(p.surname);
free(p.name);
문자열은 추상 객체, char 배열은 컨테이너로 간주합니다.문자열은 임의의 크기를 사용할 수 있지만 컨테이너는 문자열 길이보다 적어도1 이상 커야 합니다(늘 터미네이터를 보관 유지).
C는 문자열에 대한 구문 지원이 거의 없습니다.문자열 연산자는 없습니다(char-array 연산자와 char-pointer 연산자만).문자열을 할당할 수 없습니다.
하지만 함수를 호출하여 원하는 것을 달성할 수 있습니다.
그strncpy()
여기서 기능을 사용할 수 있습니다.최대한의 안전을 위해 다음 패턴을 따르는 것이 좋습니다.
strncpy(p.name, "Jane", 19);
p.name[19] = '\0'; //add null terminator just in case
또, 이 비디오의strncat()
그리고.memcpy()
기능들.
그 두 구조는 다르다.첫 번째 구조를 초기화하면 약 40바이트의 메모리가 할당됩니다.두 번째 구조를 초기화하면 약 10바이트의 메모리가 할당됩니다.(실제 양은 아키텍처에 따라 다름)
문자열 리터럴(문자열 상수)을 사용하여 문자 배열을 초기화할 수 있습니다.이래서
Person p = {"John", "Doe",30};
첫 번째 예에서는 동작합니다.
C에서는 (기존의 의미로) 문자열을 할당할 수 없습니다.
가지고 있는 문자열 리터럴("John")은 코드가 실행될 때 메모리에 로드됩니다.이러한 리터럴 중 하나를 사용하여 어레이를 초기화하면 문자열이 새 메모리 위치에 복사됩니다.두 번째 예에서는 단순히 문자열 리터럴(위치)에 포인터를 복사하고 있습니다.다음과 같은 작업을 수행합니다.
char* string = "Hello";
*string = 'C'
컴파일 오류 또는 런타임 오류를 일으킬 수 있습니다(잘 모르겠습니다).리터럴 문자열 "Hello"를 수정하고 있기 때문에 이는 잘못된 생각입니다.예를 들어 마이크로컨트롤러에서는 읽기 전용 메모리에 배치될 수 있습니다.
언급URL : https://stackoverflow.com/questions/3131319/how-can-i-correctly-assign-a-new-string-value
'programing' 카테고리의 다른 글
Vue 동적 mapGetters (0) | 2022.07.11 |
---|---|
Allow AnyOrigin Cors가 작동하지 않음Axios Vuejs (0) | 2022.07.11 |
"TypeError: 정의되지 않은 속성 'get'을 읽을 수 없습니다", Axios, Vue.JS (0) | 2022.07.11 |
Android Studio에서 작성자 템플릿 변경 (0) | 2022.07.11 |
인증되지 않은 콘텐츠와 인증된 콘텐츠를 같은 페이지에 표시하려고 할 때 콘텐츠가 깜박입니다. (0) | 2022.07.10 |