Яка різниця між
char* name
що вказує на постійний рядковий літерал, і
const char* name
Яка різниця між
char* name
що вказує на постійний рядковий літерал, і
const char* name
Відповіді:
char*
є змінним покажчиком на змінний символ / рядок.
const char*
є змінним покажчиком на незмінний символ / рядок. Ви не можете змінити вміст розташування, на яке вказує цей вказівник. Крім того, компілятори зобов'язані надсилати повідомлення про помилки, коли ви намагаєтесь це зробити. З цієї ж причини конверсія з const char *
в char*
перестарілий.
char* const
є незмінним покажчиком (він не може вказувати на будь-яке інше місце), але вміст місця, на яке він вказує, може змінюватися .
const char* const
є незмінним покажчиком на незмінний символ / рядок.
char const *
char *
помилки сегментації під час роботи?
const
якщо хочу, щоб компілятор помилився, якщо я забув і змінив дані помилково, правда?
char *name
Ви можете змінити діаграму на які name
точки, а також діаграму, на яку вона вказує.
const char* name
Ви можете змінити діаграму на які name
точки, але ви не можете змінити діаграму, на яку вона вказує.
виправлення: Ви можете змінити покажчик, але не графік, на яку name
вказує ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , див. "Приклади" ). У цьому випадку const
специфікатор стосується char
, а не зірочки.
Згідно зі сторінкою MSDN та http://en.cppreference.com/w/cpp/language/declarations , const
попереднє значення *
є частиною послідовності специфікаторів decl, тоді як const
після *
є частиною декларатора.
Послідовність специфікатора декларації може дотримуватися декілька деклараторів, тому const char * c1, c2
декларується c1
як const char *
і c2
як const char
.
Редагувати:
З коментарів, ваше запитання, здається, задає питання про різницю між двома деклараціями, коли вказівник вказує на рядковий буквал.
У такому випадку не слід змінювати графік, на який name
вказують моменти, оскільки це може призвести до невизначеної поведінки . Строкові літерали можуть бути розподілені лише в областях пам'яті для читання (визначено реалізацію), і користувацька програма ні в якому разі не повинна змінювати її. Будь-яка спроба зробити це призводить до не визначеної поведінки.
Тож єдина відмінність у цьому випадку (використання строкових літералів) полягає в тому, що друга декларація дає вам невелику перевагу. Зазвичай компілятори подадуть вам попередження у разі спроби змінити літеральний рядок у другому випадку.
#include <string.h>
int main()
{
char *str1 = "string Literal";
const char *str2 = "string Literal";
char source[] = "Sample string";
strcpy(str1,source); //No warning or error, just Undefined Behavior
strcpy(str2,source); //Compiler issues a warning
return 0;
}
Вихід:
cc1: попередження трактуються як помилки
prog.c: У функції 'main':
prog.c: 9: помилка: передача аргументу 1 'strcpy' відкидає кваліфікатори від цільового типу вказівника
Зауважте, компілятор попереджає про другий випадок, але не для першого.
name
таблицю, на яку вказуються точки в будь-якому випадку. Це може призвести до UB.
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)
constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error
constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok
// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";
lcharp[0] = 'X'; // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error
// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X'; // compile error
((char*)astr)[0] = 'X'; // ok
char *
значення призводить до помилки сегментації, оскільки ми намагаємось змінити рядковий літерал (який присутній у пам'яті лише для читання)
В жодному випадку ви не можете змінювати літеральний рядок, незалежно від того, вказується як char *
або const char *
.
Однак різниця полягає в тому, що якщо вказівник є, const char *
тоді компілятор повинен дати діагностику, якщо ви намагаєтесь змінити вказане значення, але якщо покажчик - char *
це не так.
extern ... name
та мати *name = 'X';
. У «належній операційній системі» це може вийти з ладу, але на вбудованих системах я б очікував, що це зробить щось, що стосується платформи / компілятора.
СЛУЧАЙ 1:
char *str = "Hello";
str[0] = 'M' //Warning may be issued by compiler, and will cause segmentation fault upon running the programme
Наведене вище встановлює str на вказівку на буквальне значення "Hello", яке жорстко закодирується у бінарному зображенні програми, яке позначено як пам'ять лише для читання, означає, що будь-яка зміна цього прямого рядка є незаконною, і це може призвести до помилок сегментації.
СЛУЧАЙ 2:
const char *str = "Hello";
str[0] = 'M' //Compile time error
СЛУЧАЙ 3:
char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
Перше ви можете насправді змінити, якщо хочете, друге ви не можете. Прочитайте про const
правильність (є кілька приємних посібників про різницю). Є також місце, char const * name
де ви не можете його повторно вказати.
Питання в тому, в чому різниця між
char *name
що вказує на постійний рядковий літерал, і
const char *cname
Тобто дано
char *name = "foo";
і
const char *cname = "foo";
Між двома різницями немає великої різниці, і обидва можна вважати правильними. Через довгу спадщину коду С, рядкові літерали мали тип « char[]
ні» const char[]
, і існує багато старих кодів, які також приймаються char *
замість const char *
, навіть коли вони не змінюють аргументи.
Принципова відмінність двох в цілому полягає в тому, що *cname
або cname[n]
оцінюватимуться до значень типу const char
, тоді як *name
або name[n]
оцінюються до значень типу char
, які є змінними значеннями . Відповідний компілятор необхідний для створення діагностичного повідомлення, якщо мета призначення не є зміненим значенням ; воно не повинно створювати попередження про присвоєння значень типу char
:
name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message
У будь-якому випадку від компілятора не потрібно зупиняти компіляцію; достатньо, щоб він видав попередження про присвоєння cname[0]
. Отримана програма не є коректною програмою. Поведінка конструкції не визначена . Він може вийти з ладу або ще гірше, він не може вийти з ладу і може змінити рядковий літерал в пам'яті.
Власне, char* name
це не вказівник на константу, а вказівник на змінну. Ви можете говорити про це інше питання.