В чем разница между указателем и массивом в следующем контексте?

StackOverflow https://stackoverflow.com/questions/1048749

  •  20-08-2019
  •  | 
  •  

Вопрос

#include <cstring>
int main()
    {
    char *pName = new char[10];
    char dummy[] = "dummy";
    strcpy(pName + 0,dummy);//how this is different from -->this works
    strcpy(pName[0],dummy);//this one...--> error C2664: 'strcpy' : 
                           //cannot convert parameter 1 
                           //from 'char' to 'char *'

    }
Это было полезно?

Решение

  • PNAME [0] является первым элементом в массиве символов (один персонаж)
  • Pname - это ярлык для & pname [0] (указатель на первый элемент вашего массива)

Причина, по которой вы получаете свою ошибку, заключается в том, что Strcpy ожидает указателя на символ (char*), а не к тому, что такое Pname [0])

Другие советы

При работе с указателями и массивами в C или C ++ это действительно помогает распознать их как очень отличные конструкции (я думаю, что одна из лучших книг, объясняющих это различие, - это книга «Deep C Secrets», если я правильно помню). Что грязит вода, так это тот факт, что существует одностороннее молчаливое преобразование, разрешенное от массивов в указатели (несоответствие в обращении с именами переменных), но очень важно не интерпретировать существование этого явления распада как подразумевающее. эквивалентность.

Чтобы помочь нам разобраться в этом, давайте представим идею «ячейки памяти». Мы моделируем «ячейку памяти» как два атрибута:

a) value
b) address

Затем мы можем моделировать простую переменную C ++ как наличие двух атрибутов (нам не нужны типы на этом низком уровне абстракции):

c) name  
d) memory cell

Как и большинство моделей, он имеет некоторые недостатки (не имеет отношения к массиву с более чем одним элементом, но этого достаточно для наших целей).

Так, например:

// non-array variable: name 'i', and memory cell: value=3, address=0x0A
int i = 3;

// non-array variable: name 'p', and memory cell: value=0x0A, address=0x0B
int *p = &i;

// array variable: name 'a', and memory cell: vale=4, address=0x0C     
int a[1] = { 4 };

// non-array variable: name 'b', and memory cell: value=0x0C, address = 0x0D
int (*b)[1] = &a;

// non-array variable: name 's', and memory cell: value=0x0C, address = 0x0E
int *s = &a[0];


// non-array variable: name 't', and memory cell: value=0x0C, address = 0x0F
int *t = a; // Here is the key difference! read on...

Теперь вот основное различие между переменной массива и переменной, не относящейся к аресту (указатель) C ++:

Когда имя переменной в C ++ оценивается, оно всегда оценивается со значением своей ячейки памяти с одним исключением: если переменная называет переменную массива.
Если переменная является названием массива, который он оценивает адрес ячейки памяти.
Вышеупомянутые две строки заслуживают снова прочитать.

Вот несколько примеров, которые помогут прояснить последствия (см. Приведенные выше переменные):

int k = i;  // the 'i' name evaluates to the value of its cell, so 'k' is set to 3

int *q = p; // 'p' evaluates to the value of its cell, so 'q' is set to 0x0A

int *r = a; // 'a' evaluates to the *address* of its cell, so 'r' is set to 0x0C

int (*c)[1] = b; // 'c' is set to 0x0D

Это никоим образом не должно подразумевать, что переменная массива - это такой же как переменная указателя.
Они по своей сути имеют разные типы и любую попытку относиться к ним как к такой же (IE определить имя переменной в качестве массива в одном блоке перевода, и как указатель в другой) приведет к тому, что произойдут плохие вещи.

Так что, например, не делайте этого:

// myproj_file1.cpp
int array[100] = { 0 }; // here 'array' evaluates to the *address* of the first memory cell

// myproj_file2.cpp
extern int* array; // here 'array' evaluates to the *value* of the first memory cell 
            // Assuming the linker links the two
            // what it does if you read the assembly, is something like this: 
            // extern int* array = (int*) array[0];
            // but it doesn't have to, it can do anything, since the behavior is undefined

Надеюсь, это поможет. Если вы все еще чувствуете, что дальнейшее разъяснение может помочь, пожалуйста, задайте последующий вопрос, и не стесняйтесь получить копию (библиотеку?) Книги «Secrets Deep C» :)

--
Типы функций PS и их имена и их распад не имеют отношения к большинству этого поста
PS Я также намеренно исключил, что преобразование массива в указание не происходит, когда массивы связаны с эталонными типами

Технически, strcpy(pName[0], dummy); не правильно. Даже если память была выделена на это.

Это потому что pName[0] это типа 'char', пока pName + 0 имеет тип char*. Они оба ссылаются на одну и ту же память, но по -разному.

Компилятор может затем повернуть strcpy(pName[0], dummy); в strcpy((char*) pName[0], dummy); который является опасным неявным составом. Если ваш компилятор наполовину приличный, вы получите предупреждение или ошибку (как вы видите с вашей «ошибкой C2664»).

Нет никакой разницы. Они оба будут разбиться, так как вы не выделили места для PNAME. :) [Редактировать: больше не авария - вопрос был отредактирован

Основное отличие - стилистическая, часто находится под влиянием того, что соответствует тому, как написан окружающий код - в основном доступ к массиву или в основном доступ к указателю.

(Редактировать: при условии, что вы действительно имели в виду & pname [0], как указал Брайан Бонди.)

Массив - это просто указатель автоматически (обычно), назначенный автоматически распределенному блоку памяти. Принимая пример, вы можете объявить манекен одинаково как:

char    dummy[] = "dummy";
char    *dummy = "dummy";

И затем вы можете использовать синтаксис массива или синтаксис указателя для доступа к данным:

char    ch = dummy[0];   // get the first element of the array
char    ch = *dummy;     // get the data pointed to by dummy

Оба [] а также * можно использовать указатели и массивы de re-referference, поэтому следующие эквивалентные:

array[N];
*(ptr + N);

Учитывая вторую форму, (ptr + N) все еще указатель, просто дальше вдоль массива. Вот почему он синтаксически правильно в вашем примере. ptr[N] является отменой указателя и является символом (в этом контексте).

PNAME - это указатель на недавно выделенную память. char *pName = new char[10];

Манекен также массив/указатель. char dummy[] = "dummy";

PNAME - это указатель, и указывает на базовый адрес, даже вы добавляете (PNAME + 0) все еще указывает на то же местоположение памяти, потому что ваше единственное добавление 0. strcpy(pName + 0,dummy);

strcpy используйте переменную указателя и ваше проходное значение в первом аргументе, поэтому вы получаете ошибку strcpy(pName[0],dummy)

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top