Что делает char * массивом символов? - PullRequest
12 голосов
/ 12 декабря 2011

Обычно, если вы делаете следующее:

int * i = &someint;

Это просто указатель на переменную.

Но, когда вы делаете

char * str = "somestring";

автоматически превращает его в массив.Это указатель, который делает это, или это просто синтаксический сахар для синтаксиса инициализации?

Ответы [ 6 ]

14 голосов
/ 12 декабря 2011

Нет, строковый литерал "somestring" это уже массив символов, почти наверняка созданный вашим компилятором.

То, что делает это утверждение, устанавливает str для указания на первый символ. Если бы вы посмотрели на базовый ассемблерный код, он бы выглядел следующим образом:

str314159:  db   "somestring", 0  ; all string literals here.
: :         : :
            load r0, str314159    ; get address of string
            stor r0, -24[sp]      ; store it into local var str.

В большом количестве случаев массив распадется на указатель на первый элемент этого массива (с некоторыми ограниченными исключениями, например, при выполнении sizeof).


Например, следующий код C:

#include <stdio.h>

int main (void) {
    char *somestr = "Hello";
    puts (somestr);
    return 0;
}

при компиляции с gcc -S для генерации сборки x86 дает нам (с удаленным несущественным заголовком):

.LC0:
    .string    "Hello"
    .text
.globl main
    .type      main, @function
main:
    pushl      %ebp                ; Standard set up of stack frame,
    movl       %esp, %ebp          ;   aligning and making
    andl       $-16, %esp          ;   room for
    subl       $32, %esp           ;   local variables.

    movl       $.LC0, 28(%esp)     ; Load address of string in to somestr.

    movl       28(%esp), %eax      ; Call puts with that variable.
    movl       %eax, (%esp)
    call       puts

    movl       $0, %eax            ; Set return code.

    leave                          ; Tear down stack frame and return.
    ret

Вы можете видеть, что адрес первого символа, .LC0, действительно загружен в переменную somestr. И, хотя это может быть неочевидно, .string создает массив символов, оканчивающихся символом NUL.

3 голосов
/ 12 декабря 2011

Это не указатель на переменную.Это указатель на место в памяти.Вы создаете переменную и сохраняете ее в некоторой ячейке памяти, а затем указываете указатель на эту ячейкуПричина, по которой он работает для массивов, заключается в том, что элементы массива сохраняются в памяти.Указатель указывает на начало массива.

2 голосов
/ 12 декабря 2011
char * str 

- указатель на символ. Когда вы присваиваете строку символьному указателю, он указывает на первый символ строки, а не на всю строку. Если указатель увеличивается, вы можете видеть, что он указывает на второй символ в строке. Когда вы печатаете символьный указатель, объект cout печатает символ и продолжает печатать символ, пока не появится нулевой символ (\ 0).

#include <iostream>
using namespace std;

int main()
{
    char *s = "something";
    cout << "before :" << s << endl;
    s++;
    cout << "after :" << s << endl;
}

Эта программа печатает:

~/cpp: ./stringarray
before :something
after :omething
0 голосов
/ 12 декабря 2011

Как говорили люди, str - это не массив, а только указатель на символ (первый из «что-то», поэтому s). Однако есть 2 синтаксиса сахара

1- "something" инициализировать блок памяти со всеми символами ** и добавить \0 в конце. Итак

char *str = "something";

является синтаксическим сахаром для

char *str = {'s', 'o', 'm', 'e', 't', 'h', 'i', 'n', 'g', '\0'};
              ^                                          ^^^^^
              |
              +- str

Технически, str, длиной 10 символов, а не 9. (Обратите внимание, что str указывает только на

2 -

str[5] 

является синтаксическим сахаром для

*(str + 5)      

Тогда существует соглашение, что большинство (не все) C-функции, имеющие дело со строками, ожидают, что последний символ будет \0 (чтобы знать, где он заканчивается). Некоторые другие (см. strncpy, нуждаются в длине в качестве дополнительного аргумента и могут добавлять или не добавлять '\ 0'.

0 голосов
/ 12 декабря 2011

Слово, которое вы используете "обычно", является большой частью проблемы здесь.

Я думаю, что часть того, что может сделать это запутанным, это многие функции, которые принимают char *, ищут строку в стиле ac (т.е.массив символов с нулевым символом в конце).Вот чего они хотят .Вы могли бы написать функцию, которая просто смотрела на персонажа.

Точно так же вы могли бы написать функцию, которая взяла бы int * и считала его также массивом с нулевым символом в конце, это просто не распространено.И на то есть веская причина, потому что, если вам нужно значение 0?в строках стиля c (предназначенных для отображения не двоичных данных) вы никогда не захотите, чтобы 0.

#include <iostream>

const int b_in_data[]={50,60,70,80,0};

int Display (const int * a)
{
  while ( *a != 0){
    std::cout << *a; ++a;
  }
}    

int main()
{

 int a[]={20,30,40,0};

 // or more like char* = something because compiler is making string literal for you 
 // probably somewhere in data section and replacing it with its address
 const int *b = b_in_data;

 Display(a);
 Display(b);
 return 0;
}

строки стиля C просто выбирали завершать вместо передачи размера, строки стиля B передавали вместо size.массивы целых чисел, как правило, не заканчиваются нулем, но могут быть.Сводится к "нормально".

0 голосов
/ 12 декабря 2011
int * i = &someint;

В дополнение к другим комментариям, как правило, мы можем сказать, что это указатель на расположение размера (int).Итак, когда мы получаем доступ к значению внутри «я».то есть * i, размер ячейки памяти (int) извлекается.Также арифметический расчет производится аналогичным образом.Т.е., увеличивая указатель i + 1, увеличивая + sizeof (int).Следовательно, размер извлеченных данных зависит от «типа данных» переменной.

...