Страницы

Поиск по вопросам

понедельник, 6 января 2020 г.

Помощь с указателями

#cpp #c


Всем привет, дошел до темы указателей, честно говоря, тема неприятная, поэтому сразу
к вам вопросы, товарищи. 

1) 

char *lo = "12345";
char *plo = lo; // вот так можно, это понятно
// но почему можно так? 
char **plo = lo;
или так
char **plo = *lo;


2) Что тут происходит и почему так можно делать?

main() {
char *lo = "12345";
fun(lo);
}

// так
void fun(char s[]){ // немного не понимаю, почему так делается
printf("%s", s); 
}

// или так
void fun(char *s){ // так понимаю
printf("%s", s);
}

//можно и так
void fun(char **s){ // так тоже не понимаю
printf("%s", s);
}

//тоже не проблема
void fun(char **s[]){ // ну а это вообще факинг щит какой-то
printf("%s", s);
}


А главное все варианты работают...

3) 
    main()
    {

 char *err[] = {
"Cannot Open File\n",
"Read Error\n",
"Write Error\n",
"Media Failure\n"
};
fun(err);
}

void fun(char *s[]){
  printf("%s", s[0]);
}


Понимаю, если бы написали

void fun(char **s){
  printf("%s", s[0]);
}


Но почему char *s[] работает, я не понимаю. Главное, если в main так попробую написать

main(){
*perr[] = err; 
}


то работать не будет...

Спасите... заранее благодарю, хотя бы за то, что прочитаете. Шлю флюиды добра тем,
кто ответит
    


Ответы

Ответ 1



Для начала давайте разделим понятие "работает" на "работает и все ок", "компилируется и вроде работает", "компилируется, но происходит что то странное". Второе, разделим с и с++. Многие считают, что с является подмножеством с++. Но это далеко не так. На данный момент, это языки, которые имеют просто много общего. Начнем с самого главного, которое справедливо для с/с++ a[b] == b[a] == *(a+b) То есть, эти все три выражения эквивалентны. Когда в следующий раз увидите 1[a] - не пугайтесь, это нормально, хоть и не очень применимо для продакшн кода. Отсюдова второе следствие, если закрыть глаза на некоторые особенности, то массив это и есть указатель. И в большинстве случаев *a == a[]. Теперь разберем примеры. char *lo = "12345"; в си - это почти ок. В с++ это плохо, так как "12345" - это const char*. А присваивание с потерей константности это плохо. char *plo = lo; // вот так можно, это понятно конечно можно - char* и char* // но почему можно так? char **plo = lo; а так как бы нельзя. И с++ будет ругаться, потому что с одной стороны char** , а с другой char*. Но для с это два указателя и он закрывает на это глаза. или так char **plo = *lo; Опять же, для с++ компилятора тут ужас - попытка присвоить типу char** значение типа char Но на низком уровне все ок. Указатель это просто int, char - это просто то, что может быть приведено. Компилятор си доверяет человеку. Поехали дальше. main() { char *lo = "12345"; fun(lo); } по поводу типа я уже писал. там явно не хватает const. // так void fun(char s[]){ // немного не понимаю, почему так делается printf("%s", s); } char[] это просто массив. А массив это указатель. // или так void fun(char *s){ // так понимаю printf("%s", s); } //можно и так void fun(char **s){ // так тоже не понимаю printf("%s", s); } тут формально все ок. Потому что printf будет трактовать s как char*. как я сказал выше, char*, char** это все просто int. Вызывающая функция сохранила адрес, а printf его извлек. //тоже не проблема void fun(char **s[]){ // ну а это вообще факинг щит какой-то printf("%s", s); } Здесь снова никаких "проблем". char** s[] - это просто char*** и снова тот же int. Пример сводится к предыдущему. поэтому, и пример ещё ниже - char* s[] это char** s. main(){ *perr[] = err; } а вот это точно не будет работать - код не валидный, типы переменных не известны (хотя может они где то и спрятались). Но! написать в левой части *perr - это нормально - это разыменования указателя. И эта звездочка не должна обманывать - это звездочка разыменования, а не объявления типа указателя. И квадратные скобки в этом случае лишены смысла. Но если бы там был индекс, то сразу ситуация улучшается. В целом, си старается быть недалеко от ассемблера. Поэтому подобные конструкции в си и работают. С++ старается быть более строгим и проверяет детальнее.

Комментариев нет:

Отправить комментарий