C:给定已知地址和类型,如何打印存储在其中的值?

C: given known address and type, how to print values stored in it?

我正在做C编程的作业。

#include <stdio.h>

typedef struct JustArray {
    char *x;
  } JustArray;

int main()
{
    JustArray Items[12];
    char *d = "Test";

    Items[0].x = (char *) &d;
    printf("Pointer: %p\n", &d);
    printf("Address: %u\n",&d);
    printf("Value: %s\n", d);
/*------------------------------------*/
//Knowing address of d from above, print value stored in it using Items[0].x. Cannot use &d, *d, or d.
    char *ptr;
    ptr = Items[0].x;
    printf("%p\n", Items[0].x);
    printf("%p\n", &ptr);
    printf("%s\n", ptr);

    return 0;
}

ptr 的输出也需要是 "Test",但它向我显示了奇怪的字符。任务是找到一种方法来使用 Items[0].x 中的地址信息并在控制台中打印其值 "Test"。我找不到办法...

这里的关键是注意这一行的作用:

Items[0].x = (char *) &d;

首先观察 d 是一个 char *(即在这种情况下以 null 结尾的字符串),因此 &d(引用它)必须产生一个值类型 char * * (即指向 char 的指针或指向字符串的指针)。必须转换为 char * 才能让 C 类型检查器接受代码。 [请注意,这被认为是非常糟糕的做法,因为您将一种类型的值强制转换为另一种毫无意义的类型的值。不过这只是一个练习,正是这个 "bad practice" 让它有点挑战,所以我们暂时忽略它。]

现在,要再次返回 d,只给定 Items[0].x,我们需要对上述代码行的操作进行排序 "invert"。我们必须首先将 Items[0].x 转换为其有意义的类型 char * *,然后对结果进行一次解引用以获得类型 char * 的值(即以 null 结尾的字符串)。

char *d_again = *((char * *) Items[0].x);
printf("%s\n", d_again);

还有中提琴!

记住指针的值是一个地址。指针的内容(即它的解引用,指向的值,由它寻址)是一个位于另一个地方的值(具有被指向的类型)。所以 int* 的值是另一个变量(int 类型)的地址,它存储在另一个地址。请注意,C 中的每个原始变量都是存储在某个地址中的数据的名称。

int p = 1;
上面的

p是一个int类型的var。它有 1 作为值,由 p 直接给出(所以 p == 1)。 p 有一个地址(比如 0x11111)可以用 &p 访问(所以 &p == 0x11111 ).因此,p 是一个变量的名称,其值为 int (1),地址为 0x11111(由 &p 给出)。这意味着值 1 (它是一个 int)存储在地址 0x11111.

int* q = 0x22222;
上面的

q是一个int*类型的var(指向int的指针,意思是"an address to a var of type int")。 q有一个地址为value(本例为0x22222),由q直接给出(所以 q == 0x22222)。 但是q也有一个地址(比如0x33333),可以用[=31=访问]&q(所以 &q == 0x33333)。因此,q 是变量的名称,其值是 int 的地址(0x22222,给定by q),地址为0x33333(由&q给出)。基本上,值 0x22222 (这是一个地址)存储在地址 0x33333.

您可以在 q 上使用前缀运算符 * 来取消引用它,即访问它的内容,即存储在地址 0x22222,即 q 的值。所以基本上我们有:q==0x22222&q==0x33333*q==[无论值是多少存储在地址 0x22222]。现在考虑一下:

int* r = &p;

请记住 p 的值为 1(由 [=31= 给出的 int ]p 本身)和地址 0x11111(由 &p 给出)。现在我声明了一个指向 int 的指针,称为 r 并用 p 的地址初始化它(0x11111)。因此,r 是一个指针,其值为地址(0x11111),但它也有一个地址(比如 0x44444).

运算符 * 为指针添加前缀让我们可以访问作为其值的地址的值。所以 *r 会给我们 1 因为 1 是地址 [=31= 中存储的值]0x11111,同时是r的值和p的地址。所以 r==&p (0x11111==0x11111) 和 *r==p (1==1).

现在让我们回到您的代码。当你声明一个 char* 时你已经有了一个指针,所以如果你将 %p 设置为所需格式,它的打印将是一个地址或字符串,如果您将 %s 设置为所需格式。 (%s 使函数 printf 遍历 内容 其起始地址是给定指针(当它到达 '\0' 时停止)。我修复了你的代码(并为了可读性而对其进行了一些修改)。问题是你是将指针的地址而不是指针本身发送到函数 printf.

#include <stdio.h>

typedef struct justArray
{
    char* x;
}
JustArray;

int main()
{
    //d is a pointer whose content is an address, not a char 'T'
    char* d = "Test";
    printf("Pointer: %p\n", d); //print the address (no need for &)
    printf("Address: %lu\n", (long unsigned) d); //print the address again as long unsigned)
    printf("Value: %s\n", d); //print a string because of the %s

    JustArray Items[12];
    Items[0].x = d;
    printf("%p\n", Items[0].x); //Items[0].x == d, so it prints the same address

    char* ptr = Items[0].x;
    printf("%p\n", ptr); //ptr == Items[0].x, so it prints again the same address
    printf("%s\n", ptr); //prints the string now because of the %s

    return 0;
}

这个程序的输出将是:

Pointer: 0x400734
Address: 4196148
Value: Test
0x400734
0x400734
Test