source

C의 char 배열과 char pointer의 차이점은 무엇입니까?

itover 2023. 1. 15. 10:22
반응형

C의 char 배열과 char pointer의 차이점은 무엇입니까?

C의 포인터를 이해하려고 하는데, 현재 다음과 같이 혼동되고 있습니다.

  • char *p = "hello"
    

    이것은 h부터 시작하는 문자 배열을 가리키는 문자 포인터입니다.

  • char p[] = "hello"
    

    이것은 hello를 저장하는 배열입니다.

이 두 변수를 모두 이 함수에 전달하면 어떤 차이가 있습니까?

void printSomething(char *p)
{
    printf("p: %s",p);
}

char* ★★★★★★★★★★★★★★★★★」char[] 다른 유형이지만 모든 경우에서 바로 알 수 있는 것은 아닙니다.이는 배열이 포인터로 붕괴되기 때문입니다. 즉, 유형의 표현식이char[]는 타입 중 가 있는 됩니다.char*컴파일러는 어레이를 첫 번째 요소에 대한 포인터로 자동 변환합니다.

함수 " " "printSomething과 같이 됩니다.

char s[10] = "hello";
printSomething(s);

컴파일러는 다음과 같이 기술한 것으로 간주합니다.

char s[10] = "hello";
printSomething(&s[0]);

어디 보자:

#include <stdio.h>
#include <string.h>

int main()
{
    char *p = "hello";
    char q[] = "hello"; // no need to count this

    printf("%zu\n", sizeof(p)); // => size of pointer to char -- 4 on x86, 8 on x86-64
    printf("%zu\n", sizeof(q)); // => size of char array in memory -- 6 on both

    // size_t strlen(const char *s) and we don't get any warnings here:
    printf("%zu\n", strlen(p)); // => 5
    printf("%zu\n", strlen(q)); // => 5

    return 0;
}

foo*와 foo[]는 서로 다른 유형으로 컴파일러에 의해 다르게 처리됩니다(예: 어레이가 정적으로 할당되어 있는 경우 등) 자세한 내용은 표준에서 확인할 수 있습니다.또한 런타임 수준에서는 이들 사이에 차이가 없습니다(어셈블러에서는 거의 아래 참조).

또한 C FAQ에 관련된 질문이 있습니다.

Q: 이들 초기화 간의 차이점은 무엇입니까?

char a[] = "string literal";   
char *p  = "string literal";   

p[i]에 새로운 값을 할당하려고 하면 프로그램이 크래시됩니다.

A: 문자열 리터럴(C 소스의 이중 따옴표로 둘러싸인 문자열의 정식 용어)은 약간 다른 두 가지 방법으로 사용할 수 있습니다.

  1. char a [ ]의 선언과 같이 char 배열의 이니셜라이저로서 그 배열 내의 문자의 초기값(필요한 경우 그 크기)을 지정합니다.
  2. 그 외의 장소에서는, 이름 없는 정적 문자 배열로 바뀝니다.이 이름 없는 배열은 읽기 전용 메모리에 보존될 가능성이 있기 때문에, 반드시 변경할 필요는 없습니다.표현 컨텍스트에서 어레이는 통상대로 한 번에 포인터로 변환되므로(섹션 6 참조), 두 번째 선언은 이름 없는 어레이의 첫 번째 요소를 가리키도록 p를 초기화한다.

일부 컴파일러에는 문자열 리터럴의 쓰기 가능 여부(오래된 코드 컴파일용)를 제어하는 스위치가 있습니다.또한 일부 컴파일러에는 문자열 리터럴을 const char의 배열로 정식으로 취급하는 옵션이 있습니다(오류 검출의 향상을 위해서).

질문 1.31, 6.1, 6.2, 6.8 및 11.8b도 참조하십시오.

참고 자료: K&R2 5.5장 (104쪽)

ISO 6.1.4항, 6.5.7항

근거 3.1.4항

H&S 2.7.4절 31-2페이지

C의 char 어레이와 char 포인터의 차이점은 무엇입니까?

C99 N1256 드래프트

문자열 리터럴에는 다음 두 가지 다른 용도가 있습니다.

  1. 「」를 합니다.char[]:

    char c[] = "abc";      
    

    이는 "더 많은 매직"이며, 6.7.8/14 "초기화"에서 설명합니다.

    문자열 리터럴에 의해 문자 타입의 배열을 초기화할 수 있습니다(옵션으로 중괄호로 묶음).문자열 리터럴의 연속된 문자(공간이 있거나 배열 크기를 알 수 없는 경우 끝의 늘 문자 포함)는 배열 요소를 초기화합니다.

    즉, 이것은 다음의 숏컷에 불과합니다.

    char c[] = {'a', 'b', 'c', '\0'};
    

    다른 일반 어레이와 마찬가지로c변경할 수 있습니다.

  2. 기타 모든 장소: 다음 항목이 생성됩니다.

    • 이름 없는
    • char의 배열 C와 C++의 문자열 리터럴 유형은 무엇입니까?
    • 정적 스토리지 사용
    • 수정 시 UB(정의되지 않은 동작)를 제공합니다.

    그래서 글을 쓸 때:

    char *c = "abc";
    

    이것은 다음과 같습니다.

    /* __unnamed is magic because modifying it gives UB. */
    static char __unnamed[] = "abc";
    char *c = __unnamed;
    

    「」의 .char[]로로 합니다.char *그것은 항상 합법이다.

    , 「」를 는,c[0] , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .__unnamed (UB).

    이는 6.4.5 "String Literals"에서 문서화되어 있습니다.

    5 변환 단계7에서는 문자열 리터럴 또는 리터럴에서 생성되는 각 멀티바이트 문자 시퀀스에 값 0의 바이트 또는 코드가 부가됩니다.그런 다음 멀티바이트 문자 시퀀스를 사용하여 시퀀스를 포함하기에 충분한 정적 스토리지 기간 및 길이의 배열을 초기화합니다.문자열 리터럴의 경우 배열 요소는 type char를 가지며 멀티바이트 문자 시퀀스의 개별 바이트로 초기화됩니다[...]

    6 이들 어레이의 요소가 적절한 값을 가지고 있는 경우 이들 어레이가 구별되는지 여부는 명시되어 있지 않습니다.프로그램이 이러한 배열을 수정하려고 하면 동작은 정의되지 않습니다.

6.7.8/32 "초기화"는 다음과 같은 직접적인 예를 제시합니다.

예 8: 선언

char s[] = "abc", t[3] = "abc";

"" objects ": "defined" char "defined" char 。s ★★★★★★★★★★★★★★★★★」t이치노

이 선언은 다음 선언과 동일합니다.

char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };

어레이의 내용은 변경할 수 있습니다.한편, 선언문은

char *p = "abc";

정의하다p char하고, 그 리터럴로 되어 있는 의 「 of char라고 하는 합니다.「」를 하려고 했을 .p어레이의 내용을 수정하는 동작은 정의되어 있지 않습니다.

GCC 4.8 x86-64 ELF 구현

프로그램:

#include <stdio.h>

int main(void) {
    char *s = "abc";
    printf("%s\n", s);
    return 0;
}

컴파일 및 디컴파일:

gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o

출력 내용:

 char *s = "abc";
8:  48 c7 45 f8 00 00 00    movq   $0x0,-0x8(%rbp)
f:  00 
        c: R_X86_64_32S .rodata

: 스토어 : GCC 스토어char* 있다.rodata에 없음, 에 없습니다..text.

char[]:

 char s[] = "abc";

입수처:

17:   c7 45 f0 61 62 63 00    movl   $0x636261,-0x10(%rbp)

스택에 예:%rbp를 참조해 주세요.

, 에는 ", " "가 기재되어 ..rodata ★★★★★★★★★★★★★★★★★」.text실행은 되지만 쓰기 권한이 없는 세그먼트(segment)에 있습니다.이는 다음 방법으로 확인할 수 있습니다.

readelf -l a.out

다음 내용이 포함됩니다.

 Section to Segment mapping:
  Segment Sections...
   02     .text .rodata

APUE에서 섹션 5.14:

char    good_template[] = "/tmp/dirXXXXXX"; /* right way */
char    *bad_template = "/tmp/dirXXXXXX";   /* wrong way*/

첫템플릿에서는 됩니다. 첫 번째 템플릿에서는 어레이 변수를 사용하기 때문에 이름이 스택에 할당됩니다.그러나 두 번째 이름에는 포인터를 사용합니다.이 경우 포인터 자체의 메모리만 스택에 존재합니다.컴파일러는 문자열을 실행 파일의 읽기 전용 세그먼트에 저장할 수 있도록 준비합니다.?mkstemp함수가 문자열을 수정하려고 하면 분할 장애가 발생합니다.

인용된 텍스트는 @Ciro Santilli의 설명과 일치합니다.

이와 같은 경우 효과는 동일합니다.문자열에서 첫 번째 문자의 주소를 전달합니다.

하지만 그 선언들은 분명히 같지 않다.

다음은 문자열용 메모리와 문자 포인터를 예비한 다음 문자열의 첫 번째 문자를 가리키도록 포인터를 초기화합니다.

char *p = "hello";

다음의 경우는, 문자열 전용의 메모리를 확보합니다.메모리 사용량을 줄일 수 있습니다.

char p[10] = "hello";

상수의 수 첫 상수는 수 없습니다.이것이 첫 번째 명령어입니다.p가리키고 있습니다. 번째 두 the thep는 문자열 상수로 초기화된 배열로, 그 내용을 변경할 수 있습니다.

char p[3] = "hello"는 ?ㄹ(으)ㄹ 수 있다.char p[6] = "hello"C의 문자열 끝에 '0'자가 있다는 것을 기억하십시오.

「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C」 「C 「C」 「C」 「C」 「C」는 「C」 .포인터의 값을 메모리내의 다른 장소를 가리키도록 변경할 수 있습니다만, 어레이는 작성된 후에 항상 같은 장소를 가리킵니다.
'새롭다' '삭제하다'

제가 기억하는 한 어레이는 사실 포인터의 그룹입니다.예를들면

p[1]== *(&p+1)

진실된 진술입니다.

언급URL : https://stackoverflow.com/questions/10186765/what-is-the-difference-between-char-array-and-char-pointer-in-c

반응형