2017-01-05 2 views
-3

Я пытаюсь сохранить ячейку памяти переменной evil в переменной ptr, но вместо места памяти переменная выдает значение внутри переменной, а не ее местоположение. Как переменная ptr, так и синтаксис &evil распечатывают тот же результат, который является значением переменной, а не местоположением в памяти. Может кто-то, пожалуйста, подтолкнуть меня в правильном направлении и помочь мне определить синтаксис, необходимый для хранения ячейки памяти переменной string/char в C?Указатели и символы Переменные в C

int main() 
{ 
    char *ptr; 
    char evil[4]; 
    memset(evil, 0x43, 4);//fill evil variable with 4 C's 
    ptr = &evil[0];//set ptr variable equal to evil variable's memory address 
    printf(ptr);//prints 4 C's 
    printf(&evil);//prints 4 C's 
    return 0; 
} 
+2

C++ tag! Это ИЗВЕСТНО! – user4581301

+1

'printf()' строки, не содержащей NULL, никогда не будет полезен. –

+0

Массивы немного непоследовательны в языке: 'evil' и' & evil' означают одно и то же - это справедливо только для массивов. Кроме того, вам повезло, что 'printf' работает без наличия явных 0-терминираторов в вашем массиве символов. –

ответ

3

Это нормально, потому что первый параметр printf является спецификатором формата, который является в основном char*, указывающий на строку. Ваша строка будет напечатана as-is, потому что она не содержит спецификаторов формата.

Если вы хотите отобразить значение указателя в качестве адреса, используйте %p в качестве спецификатора формата, и указатель в качестве последующего параметра:

printf("%p", ptr); 

Однако, обратите внимание, что ваш код вызывает неопределенное поведение (UB), потому что ваша строка не заканчивается нулем. Скорее всего, это было «завершено».

Также обратите внимание, что, чтобы быть «правильный код», отлитый указатель на void* при отправке его printf, потому что различные типы указателей могут отличаться на некоторых платформах, а стандарт C требует параметр, чтобы быть указатель-to void. Смотрите эту ветку для более подробной информации: printf("%p") and casting to (void *)

printf("%p", (void*)ptr); // <-- C standard requires this cast, although it migh work without it on most compilers and platforms. 
+1

'printf ("% p ", (void *) ptr);' –

+1

Ваше использование фразы «совершенный код» предполагает, что опустить бросок можно опустить. На мой взгляд, это не так. Вы всегда должны * указывать значение указателя на 'void *' при использовании его с '% p' (если только это не относится к этому типу); нет причин не делать этого. –

+1

@KeithThompson Я знаю, что в стандарте указано, что% p следует использовать с указателем void. Тем не менее, нет никакой причины, почему компилятор C не сможет без проблем преобразовать любой указатель-объект в указатель void при передаче в printf через va_list, когда во всех других случаях он отлично способен и требуется для сделайте это (согласно 6.3.2.3/1). Если приведение было необходимо, то это означает, что указатели принимают какой-то таинственный и волшебный формат при передаче в printf, но только тогда. Это не имеет никакого смысла. – Lundin

0

, если вы хотите, чтобы увидеть адрес полукокса - все без нечетности массива/указатель/распада

int main() 
{ 
    char *ptr; 
    char evil; 
    evil = 4; 
    ptr = &evil; 
    printf("%p\n",(void*)ptr); 
    printf("%p\n",(void*)&evil); 
    return 0; 
} 
+1

'% p' требует аргумент типа' void * '. Если вы хотите напечатать значение указателя другого типа, произведите его: 'printf («% p \ n », (void *) * evil);' –

0

Использование

printf(ptr);//prints 4 C's 

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

Может кто-то пожалуйста, подталкивать меня в правильном направлении

Чтобы напечатать адрес, вам нужно использовать формат %p спецификатор в вызове printf.

printf("%p\n", ptr); 

или

printf("%p\n", &evil); 

или

printf("%p\n", &evil[0]); 

См printf documentation для всех способов, которыми это можно использовать.

3

#include <stdio.h> для printf и #include <string.h> для memset.

int main() 

Вы можете уйти с этим, но int main(void) лучше.

{ 
    char *ptr; 
    char evil[4]; 
    memset(evil, 0x43, 4);//fill evil variable with 4 C's 

Это было бы более разборчивыми при замене 0x43 на 'C'. Оба они означают одно и то же (при условии набора символов на основе ASCII). Еще лучше, если не повторять размер:

memset(evil, 'C', sizeof evil); 


ptr = &evil[0];//set ptr variable equal to evil variable's memory address 

Это устанавливает ptr в адрес исходной (0-й) элемент массива объекта evil. Это не то же самое, что адрес самого объекта массива. Они имеют одинаковое расположение в памяти, но &evil[0] и &evil имеют разные типы.

Вы также можете написать это как:

ptr = evil; 

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

Взаимосвязь между массивами и указателями в C может быть запутанной.
Правило 1: Массивы не указатели.
Правило 2: прочитайте раздел 6 раздела comp.lang.c FAQ.

printf(ptr);//prints 4 C's 

Первый аргумент printf должен (почти) всегда быть строковым, строка формата. Если вы укажете ему имя переменной массива символов, и в ней должно быть % символов, могут быть плохие вещи. Если вы просто выводя строку, вы можете использовать "%s" как формат строки: (. Заметь, что я добавил строку так отображается выход правильно)

printf("%s\n", ptr); 

За исключением того, что ptr Безразлично 't указывает на строку . Строка по определению заканчивается символом null ('\0'). Ваш массив evil не является. (Вполне возможно, что там просто бывает нулевые байты только после того, как массива в памяти Не зависит от этого.).

Вы можете использовать ширину в поле, чтобы определить, сколько символов в печать:

printf("%.4s\n", ptr); 

Или, чтобы избежать ошибок, подверженных практике того, чтобы написать тот же номер несколько раз:

printf("%.*s\n", (int)sizeof evil, evil); 

найти хороший документ для printf если йо Вы хотите это понять.

(или, в зависимости от того, что вы делаете, может быть, вы должны организовать evil быть нулевым байтом в первую очередь.)

printf(&evil);//prints 4 C's 

Ах, теперь мы есть серьезные неопределенное поведение. Первый аргумент printf является указателем на строку формата; это тип const char*. &evil имеет тип char (*)[4], указатель на массив из 4 char элементов. Ваш компилятор должен был предупредить вас об этом (строка формата имеет известный тип, а следующие аргументы отсутствуют, поэтому правильность их типов зависит от вас). Если это кажется, то это связано с тем, что &evil указывает на то же место в памяти, что и &evil[0], а разные типы указателей, вероятно, имеют одинаковое представление в ваших системах, и, возможно, бывает, что происходит случайный '\0' сразу после массива - возможно, предшествующего некоторыми непечатаемыми символами, которые вы не видите.

Если вы хотите напечатать адрес вашего объекта массива, используйте формат %p. Это требует аргумент типа указателя void*, так что вам нужно бросить его:

printf("%p\n", (void*)&evil); 


    return 0; 
} 

Сведя все это вместе и добавив некоторые навороты:

#include <stdio.h> 
#include <string.h> 
int main(void) 
{  
    char *ptr; 
    char evil[4]; 
    memset(evil, 'C', sizeof evil); 
    ptr = &evil[0]; 
    printf("ptr points to the character sequence \"%.*s\"\n", 
      (int)sizeof evil, evil); 
    printf("The address of evil[0] is %p\n", (void*)ptr); 
    printf("The address of evil is also %p\n", (void*)&evil); 
    return 0; 
} 

Выход на моей системе является :

ptr points to the character sequence "CCCC" 
The address of evil[0] is 0x7ffc060dc650 
The address of evil is also 0x7ffc060dc650 
Смежные вопросы