Ошибка "Нарушение прав доступа при чтении" при попытке разыменовать указатель на указатель, переданный в функцию
Задача:
Пишу код на Си. Есть массив строк, к примеру всего 8 строк по 64 символа, т.е. char str[8][64].
Этот массив заполняется строками, переданными через аргументы командной строки.
Я хочу вывести строки массива str на экран и никаких проблем у меня не возникает, когда я делаю это в функции, где и создавал этот массив.
Я хочу сделать функцию strArrOut(char **arr, int size), которая бы выводила на экран массив строк, когда в неё передают указатель на этот массив и размер этого массива.
Но когда я пытаюсь разыменовать этот указатель в функции, то получаю ошибку "Нарушение прав доступа при чтении по адресу 0xFEFEFEFE", хотя я точно знаю, что по адресу, который содержится в переданном указателе, точно что-то есть. Долго и упорно гуглил, но наверное я слепой, либо чего-то не понимаю (Хотя по-моему в C++ я делал похожую вещь и обращался к элементам переданного массива через [ ] и всё работало, но тут не получается).
Вот код:
#include <stdio.h>
#include <string.h>
#include <locale.h>
#include <stdlib.h>
void strArrOut(char** arr, int size);
int main(int argc, char* argv[]) {
setlocale(LC_ALL, "Russian");
char str[8][64];
int strc = argc - 1;
//Заполняю массив тем, что передано через командную строку
for (int i = 1; i < strc + 1; i++) {
strcpy_s(str[i - 1], sizeof(str[i - 1]), argv[i]);
}
//Пытаюсь вывести первую строку массива - без ошибок
printf("p: %p", str);
printf("\n*p: %s", *str);
//Пытаюсь вывести первую строку массива, но передавая указатель в функцию
printf("\nВходные строки: ");
strArrOut(str, strc);
return 0;
}
void strArrOut(char** arr, int size) {
printf("\np: %p", arr); // Выдает тот же адрес, что и str
printf("\n*p: %s", *arr); // Ошибка: нарушение прав доступа при чтении по адресу 0xFEFEFEFE
//printf("\n*p: %s", arr[0]); - выдаёт ту же ошибку
}
В чем проблема? Разве я не всегда могу получить значение по адресу, если точно знаю, что за ним есть какое-то значение?
UPD: Рабочее решение: заменить строку void strArrOut(char** arr, int size); на void strArrOut(char arr[][64], int size);, так всё работает, но всё же интересно было бы услышать предложения почему нельзя разыменовать указатель char **arr. При схожей конструкции, но с передачей указателя на одномерный массив (т.е. char *arr), разыменовать указатель получается, а тут нет.
Ответы (1 шт):
char** arr - указатель на указатель char *
char str[8][64] - массив char 8 x 64
char ( * strp ) [8][64] - указатель на массив char 8 x 64
При передачи массива функции передаётся только адрес на первую строку массива. Копирование не происходит. Можно передавать адрес на сам массив. Варианты передачи :
адрес на массив :
char str[8][64];
void strArrOut(char (* arrp)[][64], int size) // или
void strArrOut(char (* arrp)[8][64], int size){
( * arrp ) [1][2] = 'x' ; }
strArrOut ( & str, strc);
адрес на первую строку массива :
char str[8][64];
void strArrOut(char arrp[8][64], int size) // или
void strArrOut(char arrp[][64], int size) // или
void strArrOut(char ( * arrp)[64], int size){
arrp [1][2] = 'x' ; }
strArrOut ( str, strc); // или
strArrOut ( & str[0], strc);
Как выглядит массив в памяти :
arr[2][3] :
[0][0] , [0][1] , [0][2] , [1][0] , [1][1] , [1][2]
все элементы находятся рядом.
* * arr :
arr[0] -> [0] , [1] , [2]
arr[1] -> [0] , [1] , [2]
arr - это массив указателей. arr[i] - это указатель на строки, эти строки находятся в различных участках памяти.