【问题标题】:What are the differences between char* and all other types of pointers in C?char* 和 C 中所有其他类型的指针有什么区别?
【发布时间】:2020-08-20 18:54:39
【问题描述】:

我注意到char* 在 C 中的工作方式与所有其他指针在 C 中的工作方式之间存在一些差异。例如,其中一个差异是: 当打印出 char 指针本身时,它会返回它的值,直到它被终止: 代码:

char* var = "Hello World";
printf("%s", var);

输出:

Hello World

但是当对其他指针执行相同操作时,它会返回存储在其中的值的地址,如下所示: 代码:

int var = 5;
int* pVar = &var;
printf("%d", pVar);

输出

//Random memory address

我还注意到,您不能像这样直接声明不是char* 的指针:

int* var = 5;

有人可以列出这些指针之间的所有差异以及为什么存在这些差异吗?谢谢

【问题讨论】:

  • 简单地说,您的第一个示例指向一个字符数组,该数组在一串字符的末尾有一个 \0 字符。 printf(%s",var) 正在寻找该 \0 字符以知道何时停止。其他指针打印它只是假设一个指针大小。
  • “当打印出 char 指针本身时” - 除非您打印的不是指针本身,而是它所指向的字符串。
  • 指针,是指针,是指针——但是type控制指针算法!也许有帮助Pointer Basics
  • @DavidC.Rankin:大部分是真的,但不是完全。指针别名规则实际上以一些奇怪的方式处理特殊情况 char*
  • 是的,你是对的,C11 Standard - §6.5 Expressions (p6,7)(称为严格别名规则)。该规则有例外。一个例外(最后一点)是可以通过char 类型的指针访问任何值。

标签: c pointers


【解决方案1】:

让我们一一解决你的每一个问题。

打印

在您的第一个代码 sn-p 中,您表明 printf 能够打印字符串。当然它打印了一个字符串。你给了它一个%s,它是一个字符串。但首先,什么是字符串?为了解释这一点,我们需要了解数组和字符。

什么是字符串?

首先,char 是什么? char 是一个单数字符(或一个 8 位数字,但对我们来说它是一个字符)。字符可以是字母(abc)m 或任何其他符号(?!.、数字,还有一些控制字符)。通常,如果你只需要一个字符,你会这样声明它:

char letter_a = 'a';

那么什么是数组?数组是一组彼此相邻的值。考虑以下代码:

int int_array[] = int[50];
int_array[0] = 1;
int_array[1] = 2;
...

在这个例子中,int_array 是什么?答案似乎很明显。这是一个数组。但除此之外还有更多。如果我们这样做呢?

printf("%d\n", *int_array);

它打印出1。为什么?因为 int_array 实际上只是一个指向数组第一个元素的指针。

那么我为什么要谈论数组呢?因为字符串只是一个字符数组。当您运行char* string = "Hello!" 时,您只需创建一个如下所示的数组:['H', 'e', 'l', 'l', 'o', '!', '\0']。 C 知道字符串一旦到达空符号 ('\0') 就结束了。

在您的第一个 sn-p 中,var 是指向字母 'H' 的指针,并且 print 语句会一直打印字符,直到达到 null。

第二个sn-p呢?

%d 不会像%s 那样取消引用变量。它只是将数字打印为有符号整数。本例中的整数就是你的整数的内存地址。

为什么不能分配指针?

你可以。你会得到一个警告,它可能会导致分段错误,但你可以尝试一下。我使用 clang 编译了您的代码示例,这就是我得到的:

test.c:1:1: warning: return type of 'main' is not 'int' [-Wmain-return-type]
void main() {
^
test.c:1:1: note: change return type to 'int'
void main() {
^~~~
int
test.c:2:7: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]
        int* var = 5;
             ^     ~
2 warnings generated.

但我不敢尝试运行它。基本上你刚刚所做的是尝试访问内存中的第五个位置,这很可能是一些操作系统的东西。你无权访问它

为什么它对字符串有效?

因为它不指向特定位置。它指向 C 为您创建的字符串的位置。您的代码大致相当于:

char h = 'H';
char e = 'e';
...
char* var = &h;

【讨论】:

    【解决方案2】:

    char* 与其他指针类型没有什么不同。它只指向一个字符。 C 中的大多数字符串操作都将其视为指向一个字符序列,并读取它直到找到一个空终止符。

    指向int 的指针可以表示指向int 值的指针,也可以表示指向整数序列开头的指针,也可以指向空指针。指针没有长度,在从其他索引中读取之前,您需要知道某物的长度。 C 字符串使用空终止符来表示结束。

    你不能这样做 int *var = 5 因为那没有意义(实际上,如果你像 int *var = (int*)5 那样转换它,如果你想访问一些映射到确切地址 0x00000005 的 I/O 寄存器可能是有意义的在一个不起眼的系统上)。指针的值保存一个内存地址。您可以做的是先创建一个整数值,例如 int myInt = 5;,然后是 int *myPointer = &myInt; 您可以通过间接运算符 * 访问 5。

    指针有很多用途,尤其是在将数据传递给不同的方法时。假设您有一个 500 字节的数据结构。您可以到处复制所有这些数据,也可以只传递一个指针值,以便一切都可以就地操作。指针也是您的基本传递引用功能,在从函数返回多个值时特别有用。在 C API 中,您通常会看到接受单个整数作为函数参数的指针,这些指针是函数的指定输出。

    printf 的%s 格式符号正在寻找一个指向字符串的指针,它是普通的 char* 指针,但它希望它在空终止符之前超过一个字符。 %d 格式符号要求单个 int 值,因此当您将指针传递到那里时,它会将其视为 int 值 - 请注意,这是未定义的行为。 %p 用于读取内存地址(指针),而不是 %d

    每种指针类型之间的主要区别在于用于索引运算的每个存储单元的大小。索引 char 指针,例如chars[10] 将返回第 11 个 char,并且在大多数现代系统上,char 是 1 个字节,因此它将返回第 10 个字节。索引int* 指针使用更宽的步幅,通常每个索引 4 个字节,因此 myInts[10] 将返回指针地址的第 11 个 int 值,但这里的每个内存步长为 4 个字节.有时人们在索引数组时只是为了方便测量字节而转换为字节大小的指针,然后再转换回他们想要读取的类型。

    【讨论】:

    • "你不能做 int *var = 5" - 你可以,如果你转换值,它很好 可以给定适当的上下文的意义。 “指针不保存值,它保存内存地址。” - 内存地址值。 “无论如何,拥有一个指向单个 int 的指针没有什么用处。” - 什么?为什么?哈哈。 “指针的目的是避免过多地复制内存。” - 很有争议。 “当您将指针传递到那里时,它正在从中读取内存地址。这就是指针包含的值。” - 不是真的,这是未定义的行为,应该使用%p。跨度>
    • 感谢您的建议。 @MarcoBonelli
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-21
    • 1970-01-01
    • 1970-01-01
    • 2010-09-30
    相关资源
    最近更新 更多