2015-01-29 5 views
2

Вот мой вопрос. в C, я видел такой код:Что такое инициализация указателя строки в C

char *s = "this is a string"; 

но тогда, s на самом деле не указывает на фактическую память? , и если вы попытаетесь использовать s для изменения строки, результат не определен.

мой вопрос в том, что является точкой назначения строки указателю ?

спасибо.

+1

Вы имеете в виду, почему бы не использовать 'char s [] =" моя строка здесь "; вместо этого? Также вы можете уточнить, что вы подразумеваете под символом «s», на самом деле не указывает на фактическое право памяти ». –

ответ

3
char *s = "this is a string"; 

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

Q1: s фактически не указывает на фактическую память справа?

Вы ошибаетесь s хранит адрес памяти, в котором хранится эта строка.

Q2: какая точка назначения строки указателю тогда?

http://en.wikipedia.org/wiki/String_literal

+0

Это не отвечает на вопрос. – juanchopanza

+0

@juanchopanza Добавление подробностей. Actaully он отвечает на вопрос, где OP неправильно понимает, что '' 'не держит ничего, что я говорю в своем ответе. – Gopi

+0

« В чем смысл инициализации указателя строки в C », все, что вы делаете, это предоставить ссылку. – juanchopanza

1

s фактически не указывает на фактической памяти правой?

Технически это указывает на постоянное запоминающее устройство. Но компилятору разрешено делать все, что захочет, если это следует за правилом as-if. Например, если вы никогда не используете s, его можно полностью удалить из вашего кода.

Поскольку он доступен только для чтения, любая попытка его модификации undefined поведение. Вы можете и должны использовать const, чтобы указать, что цель указателя неизменна:

const char* s = "Hello const"; 

мой вопрос, какова точка назначения строку указателя тогда?

Точно так же, как хранить константу любого другого типа. Вам не всегда нужно изменять строки. Но вы можете передать указатель на строку вокруг функций, которые не заботятся указывают ли они буквальным или массив вы владеете:

void foo(const char* str) { 
    // I won't modify the target of str. I don't care who owns it. 
    printf("foo: %s", str); 
} 

void bar(const char* str) {} 

char* a = "Hello, this is a literal"; 
char b[] = "Hello, this is a char array and I own it"; 

foo(a); 
bar(a); 
foo(b); 
+1

, если вы уверены, что не будете изменять строку, тогда лучше всего объявить ее как const – Mawg

+0

@Mawg Да, действительно, , Предположим, что версия C поддерживает это. Я кое-что добавлю. – juanchopanza

+0

Есть версии C без ключевого слова const? Я живу и учись! – Mawg

0

Посмотрите на этот код:

char *s = "this is a string"; 
printf("%s",s); 

, как вы можете видеть, я использовал «присвоение stringpointer». Это ясно? И знайте, что s указывает на фактическую память, но только для чтения.

0

Если вы назначаете, как это,

char *s = "this is a string"; 

Он будет храниться в памяти только для чтения. Так что это причина неопределенного поведения. В этом случае s укажет на некоторую память в области только для чтения. Если вы печатаете адрес, как это, вы можете получить некоторый адрес памяти.

printf("%p",s); 

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

+0

МОЖЕТ быть помещен в RoM, что будет вызывать неопределенное поведение – dhein

1

Когда вы делаете char *s = "this is a string";, память автоматически выделяется и заполняется этой строкой, а указатель на эту память возвращается обратно вызывающему абоненту (вы). Таким образом, вам не нужно явно помещать строку в некоторую память.

s на самом деле не указывает на фактическую память справа?

Неверно, это указывает на фактическую память, реализация реализации которой скрыта от вас. И эта память находится в секторе памяти только для чтения, так что ее нельзя изменить/изменить. Следовательно, ключевое слово const как эти литералы называются постоянными литералами.

Если вы попытаетесь использовать s для изменения строки, результат не определен.

Поскольку вы пытаетесь изменить память, которая отмечена как Read-Only.

Какая точка назначения строки указателю тогда?

Другой способ добиться того же есть

char temp[260] = {0} ; 
char *s ; 
strcpy (temp, "this is a string"); 
s = temp ; 

Здесь память temp управляется вами.

char *s = "this is a string" ; 

Здесь память управляется ОС.

1

Используя const char * вместо char [], строка будет храниться в памяти read only. Это позволяет компилятору устранить дублирование строк.

Попробуйте запустить эту программу:

#include <stdio.h> 

int main() 
{ 
    const char *s1 = "This is a string"; 
    const char *s2 = "This is a string"; 
    if (s1 == s2) { 
     puts("s1 == s2"); 
    } else { 
     puts("s1 != s2"); 
    } 
} 

Для меня это выводит s1 == s2, что означает, что струна указатели указывают на то же место памяти.

Теперь попробуйте заменить const char * с char []:

int main() 
{ 
    const char s1[] = "This is a string"; 
    const char s2[] = "This is a string"; 
    if (s1 == s2) { 
     puts("s1 == s2"); 
    } else { 
     puts("s1 != s2"); 
    } 
} 

Это выводит s1 != s2, что означает, что компилятор должен был дублировать строку памяти.

Используя char * вместо char [], компилятор может выполнить эти оптимизации, которые уменьшат размер исполняемого файла.

Также обратите внимание, что вы должны не использовать char *s = "string". Вместо этого вы должны использовать const char *s = "string". char *s является устаревшим и небезопасным. Используя const char *, вы избегаете ошибки передачи строки функции, которая пытается изменить строку.

0

Все остальные рассказывали вам о памяти только для чтения и о возможном неопределенном поведении, если вы пытаетесь изменить строку, поэтому я пропущу эту часть и ответю на вопрос: «В чем смысл назначать строку для указатель тогда? ».

Есть две причины, почему

1) Только для краткости. После присвоения строки указателю вы можете ссылаться на строку как s вместо многократного ввода «это строка». Это предполагает, конечно, что вы намерены использовать строку в нескольких вызовах функций.

2) Поскольку вы можете изменить строку, на которую ссылается указатель. Например, в следующем коде s инициализируется при условии, что код будет успешным и впоследствии будет изменен, если произойдет сбой. В конце напечатана строка, на которую наносится s.

const char *s = "Yay, it worked!!!"; 

if (openTheFile() == FAILED) 
    s = "Dang, couldn't open the file"; 

else if (readTheFile() == FAILED) 
    s = "Oops, there's nothing in the file"; 

printf("%s\n", s); 

Обратите внимание, что const char * означает, что строка, которая указывает на s не может быть изменен. Это не значит, что s не может быть изменен.

+0

иметь смысл. поэтому в основном я должен использовать «const char * s =» string "" вместо "char * s =" string ""? const char * s имеют больше смысла. и он не передаст компилятор, если я хочу изменить s [i]. но char * s передаст компилятор, если я хочу изменить s [i] и получить ошибку шины времени выполнения.так что «char * s» - это что-то не совсем «подходящее»? :) – totally

+0

@totally Yup, все верно. Ранние версии C были не очень строгими в отношении использования ключевого слова 'const'. Текущие версии лучше об этом, и, как вы сказали, причина в том, что вы хотите избежать ошибки шины выполнения, которая возникнет, если вы попытаетесь изменить постоянную память. – user3386109

0

В вашем случае указатель s просто указывает на место, которое несет первый литерал строки. Поэтому, если мы хотим изменить строку, это создает путаницу, поскольку указатель s указывает на предыдущее местоположение. И если вы хотите изменить строку с помощью указателя, вы должны позаботиться о завершении предыдущей строки (например, NULL).