2D массив как указатель на массив символов - PullRequest
3 голосов
/ 21 марта 2020

Я играю с некоторым кодом в C, а также пытаюсь понять взаимосвязь между указателями и массивами. Как вы, наверное, знаете, когда я хочу создать массив, это можно сделать так:

char * arr = "abc";

или

char arr[] = {'a','b', 'c'};

Но когда я хочу сделать 2D-массив. Это нужно сделать так Потому что массив в основном указатель. Не могли бы вы объяснить это? Спасибо.

Ответы [ 4 ]

5 голосов
/ 21 марта 2020
char * names[3];

Это не двумерный массив, это массив из трех указателей на char, если вы хотите сохранить в нем char arrays, вы должны выделить память для каждого отдельного указателя, что-то вроде:

for(size_t i = 0; i < 3; i++){
    names[i] = malloc(/*length your array of chars*/);
}

Затем вы можете сохранить char arrays, используя пример:

for(size_t i = 0; i < 3; i++){
    printf("Enter name %ld: ", i + 1 );
    scanf("%29s", names[i]); //for a malloc size of 30
}

Обратите внимание, что вы должны быть осторожны с scanf, если введенная строка длиннее, чем память, выделенная для ее хранения, вы будет иметь разрушение стека, т.е. для names[i] с размером 30, вы должны использовать спецификатор %29s вместо %s. Хотя этот подход не исключает проблем, а именно возможных символов, оставленных в буфере stdin, он определенно безопаснее.

В качестве альтернативы вы можете назначать им строковые литералы (в этом случае лучше всего объявить массив как const иначе, если вы попытаетесь отредактировать один или несколько символов, это приведет к segfault):

const char* names[3];

for(size_t i = 0; i < 3; i++){
    names[i] = "My string literal";
}

Вы также можете сделать так, чтобы они указывали на существующие char arrays:

char arr[3][10];
char* names[3];

for(size_t i = 0; i < 3; i++){
    names[i] = arr[i];
}
2 голосов
/ 21 марта 2020
char * names_1[3];

Это не указатель. Это массив указателей.

char names_2[3][10]={"one", "two", "three"};
char (*p_names_2)[10]=names_2;

Теперь это указатель на ваш 2D-массив. Просто определите функцию и попробуйте использовать ее со своими «указателями» в качестве параметров.

void print_names(char names[][10], const int row){
    for(int i=0; i<row; i++)
      puts(names[i]);
}

Теперь назовите его с:

print_names(names_2, 3); 
print_names(p_names_2, 3);
print_names(names_1, 3); //WRONG

И вы увидите разницу.

1 голос
/ 21 марта 2020
Указатель

- это тип переменной, который может содержать только адрес другой переменной. Он не может содержать никаких данных. Вы не можете хранить данные в указателе. Указатели должны указывать на область памяти.

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

char * names[3] это массив указателей, поэтому вам необходимо зарезервировать для него память и затем инициализировать ее. Вам нужно использовать что-то вроде этого:

char *name[3];
for(int i=0;i<3;i++)
{
name[i]=malloc(strlen(string)+1);
}

также вы следует также выделить память для char *arr.

char *arr=malloc(strlen(data)+1)

, а затем инициализировать ее.

1 голос
/ 21 марта 2020

char* names[3] не является строго 2D-массивом (их нет в C или C ++); это массив массивов. Таким образом, каждый элемент имен содержит просто char*, который не был инициализирован.

Обратите также внимание, что строка в стиле c является массивом символов с нулевым символом в конце, поэтому Ваш исходный arr не является строкой в ​​стиле c. Чтобы сделать строку c в стиле, вам понадобится:

char arr[] = {'a','b','c',0};

сделать из нее массив длиной 4, а не 3.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...