[c] C에서 char 문자열을 수정할 수 있습니까?
나는 포인터와 관련된 모든 종류의 C 튜토리얼과 책으로 몇 시간 동안 어려움을 겪었지만 내가 정말로 알고 싶은 것은 char 포인터가 생성되면 변경할 수 있는지 여부입니다.
이것이 내가 시도한 것입니다.
char *a = "This is a string";
char *b = "new string";
a[2] = b[1]; // Causes a segment fault
*b[2] = b[1]; // This almost seems like it would work but the compiler throws an error.
그렇다면 포인터 주소 대신 문자열 내부의 값을 변경할 수있는 방법이 있습니까?
답변
소스 코드에 “문자열”을 작성하면 해당 값을 컴파일 시간에 알아야하기 때문에 실행 파일에 직접 기록됩니다 (소프트웨어를 분리하고 그 안의 모든 일반 텍스트 문자열을 찾을 수있는 도구가 있습니다). 를 작성할 때 char *a = "This is a string"
“This is a string”의 위치는 실행 파일에 있고 a
가리키는 위치 는 실행 파일에 있습니다. 실행 가능 이미지의 데이터는 읽기 전용입니다.
해야 할 일은 (다른 답변에서 지적했듯이) 읽기 전용이 아닌 힙 또는 스택 프레임에 해당 메모리를 만드는 것입니다. 로컬 배열을 선언하면 해당 배열의 각 요소에 대해 스택에 공간이 만들어지고 문자열 리터럴 (실행 파일에 저장 됨)이 스택의 해당 공간에 복사됩니다.
char a[] = "This is a string";
힙에 일부 메모리를 할당 한 다음을 사용하여 strcpy()
해당 공간에 문자열 리터럴을 복사 하여 해당 데이터를 수동으로 복사 할 수도 있습니다 .
char *a = malloc(256);
strcpy(a, "This is a string");
malloc()
기억을 사용하여 공간을 할당 할 때마다 free()
완료되면 호출 하십시오 (읽기 : 메모리 누수).
기본적으로 데이터가 어디에 있는지 추적해야합니다. 당신이 당신의 소스에서 문자열을 쓸 때마다, 해당 문자열이 읽기 전용 (그렇지 않으면 당신은 잠재적으로 실행의 동작을 변경하는 것입니다 – 당신이 쓴 경우 상상 char *a = "hello";
하고 변화 a[0]
에 'c'
그리고 다른 곳에 썼다. printf("hello");
첫 번째를 변경하는 것이 허용되었다합니다. 의 문자이고 "hello"
컴파일러는 한 번만 저장 한 다음 printf("hello");
출력합니다 cello
!)
답변
아니요, 문자열은 읽기 전용 메모리에 저장 될 수 있으므로 수정할 수 없습니다. 수정하려면 대신 배열을 사용할 수 있습니다.
char a[] = "This is a string";
또는 예를 들어 malloc을 사용하여 메모리를 할당 할 수 있습니다.
char *a = malloc(100);
strcpy(a, "This is a string");
free(a); // deallocate memory once you've done
답변
많은 사람들이 C의 문자열 리터럴과 관련하여 char *와 char []의 차이점에 대해 혼동합니다. 다음과 같이 작성할 때 :
char *foo = "hello world";
… 실제로 foo가 일정한 메모리 블록을 가리키고 있습니다 (사실 컴파일러가이 인스턴스에서 “hello world”로 수행하는 작업은 구현에 따라 다릅니다.)
대신 char []를 사용하면 배열을 만들고 “hello world”라는 내용으로 채우겠다고 컴파일러에 알립니다. foo는 char 배열의 첫 번째 인덱스에 대한 포인터입니다. 둘 다 char 포인터이지만 char []만이 로컬로 할당되고 변경 가능한 메모리 블록을 가리 킵니다.
답변
a & b에 대한 메모리는 사용자가 할당하지 않습니다. 컴파일러는 문자를 저장할 읽기 전용 메모리 위치를 자유롭게 선택할 수 있습니다. 따라서 변경하려고하면 세그 오류가 발생할 수 있습니다. 따라서 직접 문자 배열을 만드는 것이 좋습니다. 다음과 같은 것 :char a[10]; strcpy(a, "Hello");
답변
귀하의 질문에 대한 답변이있는 것 같지만 이제 왜 char * a = “String”이 읽기 전용 메모리에 저장되는지 궁금 할 것입니다. 글쎄요, 실제로 c99 표준에 의해 정의되지 않은 상태로 남아 있지만 대부분의 컴파일러는 다음과 같은 인스턴스에 대해 이렇게 선택합니다.
printf("Hello, World\n");
c99 표준 (pdf) [페이지 130, 섹션 6.7.8] :
선언 :
char s[] = "abc", t[3] = "abc";
요소가 문자열 리터럴로 초기화되는 “일반”문자 배열 객체 s 및 t를 정의합니다. 이 선언은 char와 동일합니다.
s[] = { 'a', 'b', 'c', '\0' }, t[] = { 'a', 'b', 'c' };
배열의 내용은 수정할 수 있습니다. 반면에 선언은
char *p = "abc";
“문자에 대한 포인터”유형으로 p를 정의하고 요소가 문자열 리터럴로 초기화되는 길이가 4 인 “문자 배열”유형의 객체를 가리 키도록 초기화합니다. p를 사용하여 배열의 내용을 수정하려고하면 동작이 정의되지 않습니다.
답변
다음을 사용할 수도 있습니다 strdup
.
The strdup() function returns a pointer to a new string which is a duplicate of the string s.
Memory for the new string is obtained with malloc(3), and can be freed with free(3).
예를 들어 :
char *a = strdup("stack overflow");
답변
모두 읽기 전용 메모리에 배치되기 때문에 문자열 리터럴을 수정할 수없는 이유를 설명하는 좋은 답변입니다. 그러나 밀기 위해 밀면이를 수행하는 방법이 있습니다. 이 예를 확인하십시오.
#include <sys/mman.h>
#include <unistd.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
int take_me_back_to_DOS_times(const void *ptr, size_t len);
int main()
{
const *data = "Bender is always sober.";
printf("Before: %s\n", data);
if (take_me_back_to_DOS_times(data, sizeof(data)) != 0)
perror("Time machine appears to be broken!");
memcpy((char *)data + 17, "drunk!", 6);
printf("After: %s\n", data);
return 0;
}
int take_me_back_to_DOS_times(const void *ptr, size_t len)
{
int pagesize;
unsigned long long pg_off;
void *page;
pagesize = sysconf(_SC_PAGE_SIZE);
if (pagesize < 0)
return -1;
pg_off = (unsigned long long)ptr % (unsigned long long)pagesize;
page = ((char *)ptr - pg_off);
if (mprotect(page, len + pg_off, PROT_READ | PROT_WRITE | PROT_EXEC) == -1)
return -1;
return 0;
}
나는 이것을 const-correctness에 대한 좀 더 깊은 생각의 일부로 썼습니다. 흥미로울 것입니다 (나는 희망합니다 :)).
도움이 되었기를 바랍니다. 행운을 빕니다!