C语言中的指针和字符变量

C语言中的指针和字符变量,c,pointers,char,C,Pointers,Char,我试图将evil变量的内存位置存储在ptr变量中,但该变量不打印内存位置,而是打印变量中的值,而不是它的位置。ptr变量和&evil语法都打印相同的结果,即变量的值,而不是它在内存中的位置。有没有人能告诉我正确的方向,并帮助我确定在C中存储string/char变量的内存位置所需的语法 int main() { char *ptr; char evil[4]; memset(evil, 0x43, 4);//fill evil variable with 4 C's

我试图将
evil
变量的内存位置存储在
ptr
变量中,但该变量不打印内存位置,而是打印变量中的值,而不是它的位置。
ptr
变量和
&evil
语法都打印相同的结果,即变量的值,而不是它在内存中的位置。有没有人能告诉我正确的方向,并帮助我确定在C中存储string/char变量的内存位置所需的语法

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;
}

这是正常的,因为
printf
的第一个参数是一个格式说明符,它基本上是一个指向字符串的
char*
。您的字符串将按原样打印,因为它不包含任何格式说明符

如果要将指针的值显示为地址,请使用
%p
作为格式说明符,并将指针作为后续参数:

printf("%p", ptr);
但是,请注意,您的代码调用未定义行为(UB),因为您的字符串不是以null结尾的。很可能是因为“运气不好”

还请注意,要成为“正确的代码”,请在将指针发送到
printf
时将其转换为
void*
,因为不同类型的指针在某些平台上可能不同,并且C标准要求参数为指向void的指针。有关详细信息,请参阅此线程:


printf(“%p”,(void*)ptr);// 如果你想看到一个字符的地址-没有所有的数组/指针/衰减奇怪

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

导致未定义的行为,因为
printf
的第一个参数必须是以null结尾的字符串。你的情况不是这样

有人能把我推到正确的方向吗

要打印地址,您需要在调用
printf
时使用
%p
格式说明符

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

请参阅以了解它的所有使用方法。

对于
printf
,您需要
;对于
memset
,您需要

int main()
您可以这样做,但是
intmain(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个)元素的地址。这与数组对象本身的地址不同。它们在内存中的位置相同,但是
&evil[0]
&evil
的类型不同

你也可以这样写:

    ptr = evil;
不能分配数组,但在大多数上下文中,数组表达式隐式转换为指向数组初始元素的指针

C语言中数组和指针之间的关系可能令人困惑。
规则1:数组不是指针。
第2条:阅读本手册第6节

printf
的第一个参数应该(几乎)始终是字符串文字,即格式字符串。如果您给它一个char数组变量的名称,并且它恰好包含
%
个字符,那么可能会发生不好的事情。如果只是打印字符串,可以使用
“%s”
作为格式字符串:

    printf("%s\n", ptr);
(请注意,我添加了一个换行符,以便正确显示输出。)

除了
ptr
没有指向字符串。根据定义,字符串以空(
'\0'
)字符结尾。你的
邪恶
数组不是。(内存中的数组后面可能正好有一个空字节。不依赖于此。)

您可以使用字段宽度确定要打印的字符数:

    printf("%.4s\n", ptr);
或者,为了避免必须多次写入同一个数字的容易出错的做法:

    printf("%.*s\n", (int)sizeof evil, evil);
如果您想了解这一点,请为
printf
查找一份好的文档

(或者,根据您正在做的事情,您可能应该首先安排
evil
以null结尾。)

啊,现在我们有一些严重的未定义的行为。
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;
}

C++标签!它消失了<非空终止字符串的code>printf()
永远不会有任何用处。数组在语言中有点不一致:
evil
&evil
的意思是相同的——这只适用于数组。另外,你很幸运,
printf
在你的角色数组中没有显式的0-终止符。@leedinelcrocker:No,
evil
&evil
的意思不一样
evil
是数组对象的名称;在大多数(但不是所有)上下文中,它隐式转换为其初始成员的地址
&evil
是整个数组的地址,而不是其初始元素的地址;它的类型是
char(*)[4]
,而不是
char*
。建议阅读:@leednielcrocker:认为这是一种语言
    printf(ptr);//prints 4 C's
    printf("%s\n", ptr);
    printf("%.4s\n", ptr);
    printf("%.*s\n", (int)sizeof evil, evil);
    printf(&evil);//prints 4 C's
    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