Разница между использованием указателей символов и массивов символов - PullRequest
17 голосов
/ 27 ноября 2009

Основной вопрос.

char new_str[]="";

char * newstr;

Если мне нужно объединить в нем некоторые данные или использовать строковые функции, такие как strcat / substr / strcpy, в чем разница между этими двумя?

Я понимаю, что должен выделить память для подхода char * (строка # 2). Хотя я не совсем уверен, как.

А const char * и строковые литералы одинаковы?

Мне нужно знать больше об этом. Может кто-нибудь указать на хороший исчерпывающий контент / материал?

Ответы [ 9 ]

9 голосов
/ 27 ноября 2009

Отличным источником для устранения путаницы является Питер Ван дер Линден, эксперт по программированию на C, секреты Deep C - то, что массивы и указатели не совпадают с тем, как они адресуются в памяти.

С массивом

char new_str[];
компилятор дал new_str адрес памяти, который известен как при компиляции, так и во время выполнения, например, 0x1234, следовательно, индексирование new_str просто с помощью []. Например, new_str[4], во время выполнения код выбирает адрес, где находится new_str, например, 0x1234 (это адрес в физической памяти). добавив к нему спецификатор индекса [4], 0x1234 + 0x4, можно получить значение.

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

char *newstr
адрес, например. 0x9876, но во время выполнения этот используемый адрес является схемой косвенной адресации. Предполагая, что newstr был malloc'd
newstr = malloc(10);
, происходит то, что каждый раз, когда в коде делается ссылка на использование newstr, так как адрес newstr известен компилятору, т. Е. 0x9876, но то, на что указывает newstr, является переменной , Во время выполнения код извлекает данные из физической памяти 0x9876 (т.е. newstr), но по этому адресу есть другой адрес памяти (поскольку мы его использовали malloc), например, 0x8765 именно здесь, код извлекает данные из этого адреса памяти, который malloc присваивается newstr, то есть 0x8765.

char new_str[] и char *newstr используются взаимозаменяемо, поскольку индекс нулевого элемента массива превращается в указатель , и это объясняет, почему вы могли newstr[5] или *(newstr + 5) Заметьте, как указатель выражение используется, хотя мы объявили char *newstr, следовательно

<code>*(new_str + 1)</code> = *newstr;
ИЛИ
<code>*(new_str + 1)</code> = newstr[1];

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

Получите книгу, прочитайте ее, живите и дышите. Это блестящая книга! :)

8 голосов
/ 27 ноября 2009

Пожалуйста, просмотрите эту статью ниже:

Также смотрите в случае массива char, как в вашем случае, char new_str [], тогда new_str будет всегда указывать на основание массива. Указатель сам по себе не может быть увеличен. Да, вы можете использовать подписки для доступа к следующему символу в массиве, например: new_str[3];

Но в случае указателя на символ, указатель можно увеличить new_str++, чтобы получить следующий символ в массиве.

Также я бы предложил эту статью для большей ясности.

6 голосов
/ 27 ноября 2009

Это массив символов:

char  buf [1000];

Так, например, это не имеет смысла:

buf = &some_other_buf;

Это потому, что buf, хотя он имеет характеристики указателя типа, он уже указывает на единственное место, которое имеет для него смысл.

char *ptr;

С другой стороны, ptr является только указателем и может указывать куда-то. Чаще всего это что-то вроде этого:

ptr = buf;              // #1:  point to the beginning of buf, same as &buf[0]

или, может быть, это:

ptr = malloc (1000);    // #2:  allocate heap and point to it

или

ptr = "abcdefghijklmn"; // #3:  string constant

Для всех этих случаев в * ptr можно записать, за исключением третьего случая, когда некоторые среды компиляции определяют строковые константы как недоступные для записи.

*ptr++ = 'h';          // writes into #1: buf[0], #2: first byte of heap, or
                       //             #3 overwrites "a"
strcpy (ptr, "ello");  // finishes writing hello and adds a NUL
2 голосов
/ 27 ноября 2009

Разница в том, что один - указатель, а другой - массив. Вы можете, например, sizeof () массив. Вас может заинтересовать заглядывание здесь

1 голос
/ 27 ноября 2009

Если вы используете C ++, как показывают ваши теги, вам действительно следует использовать строки C ++, а не массивы C char.

Тип string значительно упрощает манипулирование строками.

Если по какой-то причине вы застряли с массивами char, строка:

char new_str[] = "";

выделяет 1 байт пробела и помещает в него нулевой символ-терминатор. Это немного отличается от:

char *new_str = "";

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

char *new_str;

сам по себе дает вам указатель, но ничего, на что он указывает. Он также может иметь случайное значение, если он локальный для функции.

То, что люди обычно делают (в C, а не в C ++), это что-то вроде:

char *new_str = malloc (100); // (remember that this has to be freed) or
char new_str[100];

чтобы получить достаточно места.

Если вы используете функции str..., вы в основном отвечаете за то, чтобы у вас было достаточно места в массиве char, чтобы вы не получили всевозможные странные и замечательные методы отладки кода. Если вы используете настоящие строки C ++, вам предстоит проделать большую работу.

1 голос
/ 27 ноября 2009

Тип первого типа char [1], второго типа char *. Разные типы.

Выделите память для последнего с malloc в C или new в C ++.

char foo[] = "Bar";  // Allocates 4 bytes and fills them with
                     // 'B', 'a', 'r', '\0'.

Размер здесь подразумевается из строки инициализатора.

Содержимое foo является изменяемым. Вы можете изменить foo[i], например, где i = 0..3.

OTOH, если вы делаете:

char *foo = "Bar";

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

foo[i] = 'X';  // is now undefined.
0 голосов
/ 25 октября 2016

Чтобы дифференцировать их на стороне выделения памяти:

// With char array, "hello" is allocated on stack
char s[] = "hello";

// With char pointer, "hello" is stored in the read-only data segment in C++'s memory layout.
char *s = "hello";

// To allocate a string on heap, malloc 6 bytes, due to a NUL byte in the end
char *s = malloc(6);
s = "hello";
0 голосов
/ 11 июля 2010
char new_str[]="abcd";  

Указывает массив символов (строку) размером 5 байтов (один байт для каждого символа плюс один для нулевого терминатора). Таким образом, он хранит строку «abcd» в памяти, и мы можем получить доступ к этой строке, используя переменную new_str.

char *new_str="abcd";  

Указывает, что строка 'abcd' хранится где-то в памяти, а указатель new_str указывает на первый символ этой строки.

0 голосов
/ 27 ноября 2009

Если вы в c ++, почему бы не использовать std :: string для всех ваших потребностей в строке? Особенно все, что связано с конкатенацией. Это избавит вас от многих проблем.

...