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.