C에서 char 문자열을 수정할 수 있습니까?


81

나는 포인터와 관련된 모든 종류의 C 튜토리얼과 책으로 몇 시간 동안 어려움을 겪었지만 내가 정말로 알고 싶은 것은 char 포인터가 생성되면 변경할 수 있는지 여부입니다.

이것이 내가 시도한 것입니다.

그렇다면 포인터 주소 대신 문자열 내부의 값을 변경할 수있는 방법이 있습니까?

답변:


158

소스 코드에 "문자열"을 작성하면 해당 값을 컴파일 시간에 알아야하기 때문에 실행 파일에 직접 기록됩니다 (소프트웨어를 분리하고 그 안의 모든 일반 텍스트 문자열을 찾을 수있는 도구가 있습니다). 를 작성할 때 char *a = "This is a string""This is a string"의 위치는 실행 파일에 있고 a가리키는 위치 는 실행 파일에 있습니다. 실행 가능 이미지의 데이터는 읽기 전용입니다.

해야 할 일은 (다른 답변에서 지적했듯이) 읽기 전용이 아닌 힙 또는 스택 프레임에 해당 메모리를 만드는 것입니다. 로컬 배열을 선언하면 해당 배열의 각 요소에 대해 스택에 공간이 만들어지고 문자열 리터럴 (실행 파일에 저장 됨)이 스택의 해당 공간에 복사됩니다.

힙에 일부 메모리를 할당 한 다음을 사용하여 strcpy()해당 공간에 문자열 리터럴을 복사 하여 해당 데이터를 수동으로 복사 할 수도 있습니다 .

malloc()기억을 사용하여 공간을 할당 할 때마다 free()완료되면 호출 하십시오 (읽기 : 메모리 누수).

기본적으로 데이터가 어디에 있는지 추적해야합니다. 당신이 당신의 소스에서 문자열을 쓸 때마다, 해당 문자열이 읽기 전용 (그렇지 않으면 당신은 잠재적으로 실행의 동작을 변경하는 것입니다 - 당신이 쓴 경우 상상 char *a = "hello";하고 변화 a[0]'c'그리고 다른 곳에 썼다. printf("hello");첫 번째를 변경하는 것이 허용되었다합니다. 의 문자이고 "hello"컴파일러는 한 번만 저장 한 다음 printf("hello");출력합니다 cello!)


12
마지막 섹션에서는 읽기 전용이어야하는 이유에 대해 많이 설명했습니다. 감사합니다.
CDR

1
-1 : const char * 사용을 지시하지 않으며 리터럴 문자열이 실행 가능 메모리에 저장된다는 보장은 없습니다.
Bastien Léonard 2009-06-18

내가 제공 한 두 가지 솔루션에 대해 const가 필요하지 않습니다. 또한 문자열이 컴파일 시간에 알려지고 실행 파일로 컴파일 된 경우 다른 곳에 저장 될까요? gcc에서 char * a = "hallo."; 또는 char b [] = "hello.";, 어셈블리 출력 "LC0 : .ascii"Hallo. \ 0 "LC1 : .ascii"Hello. \ 0 ""둘 다 실행 가능 메모리에 있습니다 ... 언제 그렇지 않습니까? ?
Carson Myers

1
GCC 4.4로 방금 시도한 결과 .rodata (읽기 전용 데이터)에 리터럴 문자열을 넣습니다. objdump와 어셈블리 목록을 확인했습니다. 나는 표준 리터럴 문자열을 읽기 전용으로 요구 하지 않는다고 생각 하므로 .data에 넣을 수도 있다고 생각합니다.
Bastien Léonard 2009-06-19

또한 포인터를 const로 한정하지 않는 이점이 없습니다. 나중에 문자열을 변경하기로 결정하면 버그를 숨길 수 있습니다.
Bastien Léonard

29

아니요, 문자열은 읽기 전용 메모리에 저장 될 수 있으므로 수정할 수 없습니다. 수정하려면 대신 배열을 사용할 수 있습니다.

또는 예를 들어 malloc을 사용하여 메모리를 할당 할 수 있습니다.


5
코드 완성을 위해 free () 호출도 추가하면 좋을 것입니다.
Naveen 2009-06-18

15

많은 사람들이 C의 문자열 리터럴과 관련하여 char *와 char []의 차이점에 대해 혼동합니다. 다음과 같이 작성할 때 :

... 실제로 foo가 일정한 메모리 블록을 가리키고 있습니다 (사실 컴파일러가이 인스턴스에서 "hello world"로 수행하는 작업은 구현에 따라 다릅니다.)

대신 char []를 사용하면 배열을 만들고 "hello world"라는 내용으로 채우겠다고 컴파일러에 알립니다. foo는 char 배열의 첫 번째 인덱스에 대한 포인터입니다. 둘 다 char 포인터이지만 char []만이 로컬로 할당되고 변경 가능한 메모리 블록을 가리 킵니다.


7

a & b에 대한 메모리는 사용자가 할당하지 않습니다. 컴파일러는 문자를 저장할 읽기 전용 메모리 위치를 자유롭게 선택할 수 있습니다. 따라서 변경하려고하면 세그 오류가 발생할 수 있습니다. 따라서 직접 문자 배열을 만드는 것이 좋습니다. 다음과 같은 것 :char a[10]; strcpy(a, "Hello");


1
문자 배열의 문제는 char 배열의 포인터를 함수에 전달하여 거기에서 문자열을 조작 한 다음 다시 보낼 수 있다는 것입니다. 불행히도 malloc을 사용해야하는 것 같습니다.
Matthew Stopa

1
아니요 스택에 할당 된 개체를 계속 사용할 수 있습니다. 예를 들어 함수가있는 경우 void f (char * p); 그런 다음 main ()에서 f (a)를 전달할 수 있습니다. 이것은 첫 번째 문자의 주소를 함수에 전달합니다. 또한 malloc ()을 사용하기로 결정했다면 free ()를 사용하여 메모리를 해제하는 것을 잊지 마십시오.
Naveen 2009-06-18

5

귀하의 질문에 대한 답변이있는 것 같지만 이제 왜 char * a = "String"이 읽기 전용 메모리에 저장되는지 궁금 할 것입니다. 글쎄요, 실제로 c99 표준에 의해 정의되지 않은 상태로 남아 있지만 대부분의 컴파일러는 다음과 같은 인스턴스에 대해 이렇게 선택합니다.

c99 표준 (pdf) [페이지 130, 섹션 6.7.8] :

선언 :

요소가 문자열 리터럴로 초기화되는 "일반"문자 배열 객체 s 및 t를 정의합니다. 이 선언은 char와 동일합니다.

배열의 내용은 수정할 수 있습니다. 반면에 선언은

"문자에 대한 포인터"유형으로 p를 정의하고 요소가 문자열 리터럴로 초기화되는 길이가 4 인 "문자 배열"유형의 객체를 가리 키도록 초기화합니다. p를 사용하여 배열의 내용을 수정하려고하면 동작이 정의되지 않습니다.


4

다음을 사용할 수도 있습니다 strdup.

예를 들어 :


질문에 대한 답은 아니지만 여전히 매우 편리한 기능입니다. 감사합니다!
mknaf 2014 년

1
에 대해 가르쳐 주셔서 +1 strdup. 그래도 언제 사용하고 싶은지 잘 모르겠습니다.
Z boson

와 같은 작업을 수행 var = malloc(strlen(str) + 1); strcpy(var, str);할 때는 아마도 strdup대신 사용해야 합니다.
Maxime Chéramy 2014 년

3

모두 읽기 전용 메모리에 배치되기 때문에 문자열 리터럴을 수정할 수없는 이유를 설명하는 좋은 답변입니다. 그러나 밀기 위해 밀면이를 수행하는 방법이 있습니다. 이 예를 확인하십시오.

나는 이것을 const-correctness에 대한 좀 더 깊은 생각의 일부로 썼습니다. 흥미로울 것입니다 (나는 희망합니다 :)).

도움이 되었기를 바랍니다. 행운을 빕니다!


문자열 리터럴을 변경하는 것은 정의되지 않은 동작입니다.
Steohan

0

문자열을 읽기 전용 메모리 버퍼가 아닌 다른 메모리 버퍼에 복사하고 수정해야합니다. 문자열을 복사하려면 strncpy ()를 사용하고, 문자열 길이를 감지하려면 strlen ()을 사용하고, 새 문자열에 대한 버퍼를 동적으로 할당하려면 malloc () 및 free ()를 사용하십시오.

예를 들어 (의사 코드와 같은 C ++) :


0

6
malloc에는 1 바이트가 더 필요합니다. strcpy가 예상하고 복사 할 NULL 종료 문자를 잊지 마십시오. 이것은 매우 빈번한 실수입니다.
xcramps
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.