kpa6uu
@kpa6uu
Программист Талибана [Пыхерский Алибаба]

Почему возникает проблема с указателем в C?

Прошу помочь разобраться с проблемой следующего кода. В C новичок.
#include <stdio.h>
#include <string.h>

void ptrTest(char * testString);

int main(int argc, const char * argv[]) {
    char * superString = "qwe rty uio";
    
    ptrTest(superString);
    
    return 0;
}

void ptrTest(char * testString) {
    printf(testString);
    printf("\n");
    printf(*testString);
}

Знаю, что printf нужно использовать вместе с шаблоном, но пока так.

В коде я хотел вывести указатель, а потом получить значение, на которое он указывает, путём разыменования.

Компилится нормально, но после запуска возникает ошибка на строке
printf(*testString);

EEmu3GBvbW4.jpg

Полный вывод:
2nVkDafu_3c.jpg

Везде говорится, что для получения значения, находящегося по адресу указателя, необходимо его разыменовать.
Но в этом случае он автоматически разыменовывается, насколько я вижу.

Скорее всего я не прав.
  • Вопрос задан
  • 286 просмотров
Решения вопроса 4
vesper-bot
@vesper-bot
Любитель файрволлов
Тип первого параметра у printf является char*, в итоге строка разыменовывается внутри printf при печати и парсинге шаблонов. Попытка передать *teststring вызывает передачу значения строки, имплицитно преобразованного в указатель, в итоге printf пытается разыменовать 4 символа строки и с закономерным результатом получает AV (access violation, 0xC0000005, segmentation fault core dumped и другие названия).

Поздравляю с успешным выстрелом себе в ногу. :)
Ответ написан
terrier
@terrier
Когда мы заходим в функцию ptrTest указатель testString указывает на начало некоторой области памяти, в которой, как мы понимаем лежит строка "qwe rty uio" (а за ней нуль-терминатор).
Функция printf, как нам указывает, например, документация своим первым параметром принимает как раз указатель на строку, которую нужно вывести. По этому первый пример работает как работает (правильно).
Когда вы разыменовываете указатель testString (который, напомню указывает на начало строки "qwe rty uio", то есть на букву "q") вы получаете ascii-код первой буквы этой строки. В вашем случае 0x71. Вы передаете его в функцию printf, интерпретируя как значение адреса некоторой строки, однако 0x71 - адрес невалидный. Вот потому и ошибка доступа.

В коде я хотел вывести указатель, а потом получить значение, на которое он указывает, путём разыменования.

Само значение указателя ( то есть число, обозначающее адрес в памяти ) выводим так
printf("%p\n", testString)
Значение, на которое он указывает
printf("%c", *testString)
- указывает, как мы помним на букву "q"
Ответ написан
Комментировать
@Carver182
инженер-программист
testString это адрес буквы "q" в вашей строке(что-то типа 0х0A1F), *testString это переменная типа char, т.е. ASCII код.
Ты передаешь в функцию, которая ожидает адрес, букву "q" которая имеет аски код, который в свою очередь распознается как адрес и разыменовывается и скорее всего он ссылается на системную память от того и падает.
Ответ написан
Комментировать
dio4
@dio4
team leader, system engineer, master of sports
#include <stdio.h>
#include <string.h>

void ptrTest(const char * ); //здесь имя не нужно

int main(int argc, const char * argv[]) {
    const char * superString = "qwe rty uio"; // тк  "qwe rty uio" это строковый литерал (константа), то используйте const char * 
    
    ptrTest(superString);
    
    return 0;
}

void ptrTest(const char * testString) {
    printf("%s\n", testString); //выведет строку. 
    printf("\n");
    printf("%p\n", testString); //выведет адрес 1-го элемента строки (имя массива - есть адрес его 1-го элемента)
}

/*
У меня(но суть такая же будет и в windows):
Linux alexander-Inspiron-3521 3.13.0-74-generic #118-Ubuntu SMP Thu Dec 17 22:52:10 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Вывод в консоли
$ gcc toster_ru.c -o toster_ru && ./toster_ru
qwe rty uio

0x4006b4
*/
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы