singlepost

Указатели в С << На главную или назад  

Привет.
Вопрос такой :
Почему указатели типа char не нуждаются в раскрытии.
Например :

void syntax_error(int num)
{
static char *err[] = {
"Нельзя открыть файл\n",
"Ошибка при чтении\n",
"Ошибка при записи\n",
"Некачественный носитель\n"
};

printf("%s", err[num]);
}

казалось бы перед err[num] должен быть оператор *

21 ответов в теме “Указатели в С”

  1. 20
    Нгамдкхе Кверос ответил:

    Подмогаев Свят, понимаешь, в функцию ты всегда передаёшь значение, дело только в том значение чего.
    по %d функция хочет значение числа и расчитывает что получила именно его в наборе полученых байт, по %s она хочет адрес начала строки, и если транслятор прошёл то при вызове функция будет думать что этот набор полученых ею байт это адрес начала строки.

  2. 19
    Подмогаев Свят ответил:

    вся проблема сводилась к этому :
    "Просто строка – ето адрес первого символа, а другие типи – ето самая ячейка памьяти… Тоесть %s – надо адрес, %d(f, и др.) – надо взять адрес…"

    спасибо за разъяснения

  3. 18
    Олег Рак ответил:

    Тут уже все говорили но возьмусь все ето обьеденить…
    Значит так, строка – ето всеравно что масив чаров… если обьявить char *a = "Some string", то для разпечатки всего надо сказать прінтефу, что ето строка – %s. Если ето строка, то есть масив чаров, то надо передать адрес первого елемента. Тогда распечатается все до символа конца строки '\0', он добавляется автоматически в конец строки в даном примере. Если надо один символ – то %с и тогда *а…
    char *err[] – ето масив указателей, то есть масив масивов(двумерний)

    начало (*err или err[0]) -> "Нельзя открыть файл\n"
    *(err+1) илиerr[1]->"Ошибка при чтении\n"
    *(err+2) илиerr[2]->"Ошибка при записи\n"
    *(err+3) илиerr[3]->"Некачественный носитель\n"

    Примерна такова его структура в памяти…

    Просто строка – ето адрес первого символа, а другие типи – ето самая ячейка памьяти… Тоесть %s – надо адрес, %d(f, и др.) – надо взять адрес…

  4. 17
    Тоша Мартынов ответил:

    "во-первых, в 32-битной системе указателю выделяется 4 байта"
    согласен, ляпнул не совсем верно ;)
    сайзами и пользуюсь…

  5. 16
    Нгамдкхе Кверос ответил:

    "во-первых, в 32-битной системе указателю выделяется 4 байта"
    с тойже степенью достоверности можно говорить что в байте 8 бит, т.е. если вы так говорите то для вас оно скорей всего так и есть, хотя на самом деле есть варианты так что лучше не принимать эту догму а честно пользоваться сайзами.

    строка это массив чаров заканчивающийся нулевым символом. под "передать строку" подразумевается передать указатель на первый символ строки. так что принтф по %s расчитывает получить именно указатель на начало строки, а по %d целое.

  6. 15
    Нгамдкхе Кверос ответил:

    Глеб 'Whatup' Загребалов, транслятор в данном случае тупой и встречая "строка"понимает что это константа и выделяет под неё память в сегменте данных и заполняет значением, точно также как встречая цифры выделяет память под них вне зависимости от того в каком месте встретил.

  7. 14
    Глеб Загребалов ответил:

    Насчет памяти – если ты инициализируешь указатель СРАЗУ же в его объявлении, то память выделится автоматически:

    char *str = "O_o";

    Если же потом – нет, и это таки да, чревато. Поправьте, если ошибаюсь.

    Алсо, для адресов есть православный спецификатор %p.

  8. 13
    Кристиан Баринов ответил:

    an†ik
    Это понятно )

  9. 12
    Тоша Мартынов ответил:

    Кристиан Prayer Баринов,
    "err[num] – это уже эл-т массива, поэтому звездочка не нужна."

    *(err+num) – то же самое, только со звездочкой ;)

  10. 11
    Тоша Мартынов ответил:

    так… по парядку…
    имя переменной – это адрес, ссылка на значение.
    указатель – переменная, хранящая адрес, указывающий где хранится значение
    тогда при выводе строки с использование шаблона %s, он переходит по адресу, который содержит указатель. а при %d – читает значение переменной.

  11. 10
    Кристиан Баринов ответил:

    Свят
    Извиняюсь, если я не понял тебя

    ViLco
    Может, я ошибаюсь, но в printf(), как я помню, передавать нужно значение переменной (конечно, строка всегда передается как указатель)

  12. 9
    Подмогаев Свят ответил:

    то есть для %s передаем указатель , а для %d значение ?

  13. 8
    Тоша Мартынов ответил:

    во-первых, в 32-битной системе указателю выделяется 4 байта, хотя тип char – всего один.
    во-вторых, работа со строками происходит так: от какого-либо адреса до нулекого байта (признак конца строки). наверное в этом и причина

  14. 7
    Vitaly Martynovich ответил:

    Prayer, вы не обижайтесь только, но вы не больше автора похоже понимаете.
    Потому что когда парсер встречает %s в шаблоне, он считает что в соответствующем параметре находится указатель на начало строки, а %d – считает что ему подсунули число (в данном случае это число – адрес переменной number)

  15. 6
    Подмогаев Свят ответил:

    Кристиан Prayer Баринов
    К чему выделять память ,если по умолчанию память выделяется в таблице строк ?

    "Грубая ошибка: printf("%d",point1)"

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

    эмс..переменная-то объявлена, а значение – не принципиально.

    ты видимо не понял моей мысли.
    а мысль в следующем :
    в случае с чарами мы в printf() передаем указатель, а случае ином мы этот самый указатель разименовываем

  16. 5
    Кристиан Баринов ответил:

    > char *point1;
    > point1 = "any string";
    Примечание: не вижу выделения памяти под указатель. Это неправильно. Выдели память

    > int *point1;
    > int number;
    > point1 = &number;
    В point1 ты записываешь адрес переменной number. В чем проблема? Все отлично ;) . Только есть несколько недочетов:
    1. Грубая ошибка: printf("%d",point1) печатает не значение переменной point1, а значение ее адреса. Запомни: Си – язык военный. Скажешь ему катить квадратное – покатит. Это тебе не Java с эксептионами
    Нужно так: printf("%d",*point1)
    2. int number не ининициализирована

    Попробуй теперь откампилить вот этот простой примерчик:
    int main()
    {
    int *point1;
    int number = 100;
    printf("%d\n", number);
    point1 = &number; // берем адрес перем number
    *point1 = 20; // меняем значение по этому адресу
    printf("%d\n", *point1);
    printf("%d\n", number); // здесь ты видишь, что оно изменилось
    _getch();
    return 0;
    }

    Пример наглядный и показывает, что такое, когда одна переменная (point) содержит адрес другой, и что через это адрес можно менять значение переменной number

  17. 4
    Подмогаев Свят ответил:

    просто немножко указатели у меня в голове не укладываются))
    логика такая :
    допустим есть такой код :

    void func1(void){
    char *point1;

    point1 = "any string";
    printf("%s",point1);
    }

    так что получается..мы указателю(адресу) приравниваем строковую константу

    а если сделать так

    void func1(void){
    int *point1;
    int number;

    point1 = &number;
    printf("%d",point1);
    }

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

  18. 3
    Александр Васюченко ответил:

    Чтобы было понятнее объясню так:

    *err[]- это массив строк (массив указателей на строки)
    err[num] – строка (указатель на строку)

  19. 2
    Кристиан Баринов ответил:

    err[num] – это уже эл-т массива, поэтому звездочка не нужна.

    Оператор "*" нужен для взятия значения от адреса! В err[num] это сделал уже скобка

    А если хочешь, чтобы было со звездочкой, то скомпиль это:
    int main()
    {
    char *err[] = {
    "I love Russia\n",
    "USA\n",
    "Norway\n",
    "I want to be with you\n"
    };
    for (int i = 0; i < 4; i++)
    printf("%s", *(err + i)); // опять адресная арифметика
    _getch();
    return 0;
    }

    Поставил латиницу – а то плохо русские буквы отображ

  20. 1
    Nickolay White ответил:

    char * это не обязательно указатель на элемент типа char.
    Это может быть указателем на начало массива из char.
    Соответственно с-строки хранятся в виде массивов из char.
    И не надо разыменовывать.

    Можешь конечно сделать *err[num], но тогда у тебя выводится первый символ.
    Например *err[0] == 'Н'

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.