Что делает char * массив символов?
Обычно, если вы делаете следующее:
int * i = &someint;
Это просто указатель на переменную.
Но, когда вы делаете
char * str = "somestring";
он автоматически превращает его в массив. Является ли это указателем, который это делает, или это просто синтаксический сахар для синтаксиса инициализации?
Ответы
Ответ 1
Нет, строковый литерал "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.
Ответ 2
Это не указатель на переменную. Это указатель на место в памяти. Вы создаете переменную и сохраняете ее в некоторой ячейке памяти, а затем указываете указатель в этом месте. Причина, по которой он работает для массивов, состоит в том, что элементы массива сохраняются обратно в память. Указатель указывает на начало массива.
Ответ 3
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
Ответ 4
int * i = &someint;
В дополнение к другим комментариям. Как правило, мы можем сказать, что это указатель на расположение размера (int). Итак, когда мы получаем доступ к значению внутри "i". т.е. * i, извлекается ячейка памяти sizeof (int). Кроме того, арифметический расчет выполняется таким же образом. То есть, увеличивая указатель я + 1, увеличивается + sizeof (int). Следовательно, размер полученных данных зависит от типа данных переменной.
Ответ 5
Слово, которое вы используете "обычно", является большой частью проблемы здесь.
Я думаю, что часть того, что может сбить с толку, - это многие функции, которые принимают char *
, ищут строку стиля c (т.е. нулевой конец символьного массива). То, что они хотят. Вы можете написать функцию, которая просто смотрела на персонажа.
Аналогичным образом вы могли бы написать функцию, которая взяла 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 передали размер. массивы ints обычно не являются нулевыми, но могут быть. Доходит до "обычно".
Ответ 6
Как говорили люди, str
- это не массив, а только указатель на char (первый из "что-то", поэтому 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".