【问题标题】:Differences between pointer initializations指针初始化的区别
【发布时间】:2009-08-14 00:14:42
【问题描述】:

我正在使用标准,K&R C.

给定:

const char a[] = {1, 2, 3};
const char *p = NULL;

这两个语句是否等效:

  1. *p = a;

  2. p = a;

他们每个人都在 sn-p 的第三行。

1 和 2 看起来肯定不一样。

那么两者有什么区别呢?

【问题讨论】:

  • 顺便说一句,它不会影响答案,但没有“标准 K&R C”之类的东西。在“C 编程语言”第一版中描述的 K&R C 现在已经过时了。标准 C 有两种主要口味,C89/C90 和 C99。 C89 也称为“ANSI C”,因为 ANSI 于 1989 年发布,然后 ISO 于 1990 年发布了一个实际上相同的标准。C99 以另一个顺序发布 - 首先是 ISO,然后是 ANSI。 K&R 书的第二版和第三版与 ANSI C 相关,但我不认为这使它成为“标准 K&R C”

标签: c pointers


【解决方案1】:

没有。

p = a 初始化指针以指向其他东西(通常它复制另一个指针,或者您将指向一个引用,ala p = &a

*p = a 初始化 p 所指的内容。您正在“取消引用”(查看) p 指向的内容。如果 p 像您的示例中那样指向 NULL,您将崩溃(这很好!您不想意外访问某些内容并弄乱您的程序)。

在这种情况下,p = a 将指向数组 a[] 的第一个,*p = a 将尝试更改数组的第一个(它不起作用;您将它声明为 const)。

这是一个 C++ 的小示例程序,其语法与 C 几乎相同。

#include <iostream>

int main()
{
    char arr[5] { 'a', 'b', 'c' }; // arr[3] and arr[4] are set to 0
    char *ptr = arr; //point to 'a'

    for (int i = 0; i != 5; i++)
    {
       *ptr = 'f'; //this changes the array
       ptr++; //this changes what the pointer points to; moves it to next in array
    }

    for (int i = 0; i != 5; i++)
    {
        std::cout << *ptr << " ";
    }

    //outputs f f f f f
}

【讨论】:

  • "和 *p = a 将尝试更改数组的第一个(它不起作用;您已将其声明为 const)。"轻微修正:p指向NULL; a 有数组。正如您在第二段中所说,他正在取消引用 NULL;不改变数组,正如你在第三个中所说的那样。
【解决方案2】:

* 运算符就是我们所说的dereference operator。要了解它的作用,您必须准确了解指针是什么。

当你这样做时

char *p;

“变量”p 使用的内存量与普通字符不同,它使用更多内存:它使用正确识别计算机中内存位置所需的内存量。因此,假设您使用 32 位架构,变量 p 占用 4 个字节(而不是您期望的 1 个字节)。

所以,当你这样做时

p = a;

您清楚地看到您正在更改变量 p 的内容,也就是说,您在其中放入了另一个 32 位数字:您正在更改它指向的地址。

该行执行后,p的值就是字符数组a的内存地址。

现在是取消引用运算符。当你这样做时

*p = 'Z';

您是在告诉编译器您要将值“Z”存储在 p 指向的地址上。因此,在这一行之后 p 的值保持不变:它继续指向同一个地址。 这个地址的值发生了变化,现在包含“Z”。

那么,最终效果

char a[] = {'a', 'b', 'c'};
char p = a;
*p = 'Z';

和把数组a的第一个位置改成'Z'一样,也就是:

char a[] = {'a', 'b', 'c'};
a[0] = 'Z';

注意: 使指针指向数组时有区别:包含数组的变量只包含第一个元素的地址,所以 a 是同“数组的起始地址”。

通常您会看到 & 运算符。它是用于获取变量的内存地址的运算符。例如:

int number = 42;
int pointer = &number;
printf("%d", *pointer);

这里我们都有。第一行创建一个整数变量,并在其中存储 42。

第二行创建一个指向整数的指针,并在其中存储变量号的地址

第三行读取指针指向的地址上的值

因此,诀窍是将 *x 读取为 x 所指向的地址,并将 &x 读取为 x 的地址

【讨论】:

  • p = a 不是快捷方式。初始化指向 p = &amp;a[0] 之类的数组的指针会使人们更加困惑。
【解决方案3】:

第一个解引用空指针,并尝试为其分配数组的地址。这将是一个编译器错误,因为char != char []。如果不是,它可能会崩溃。

第二个设置p 指向数组。

【讨论】:

    【解决方案4】:

    我认为你弄错了:

    char a[8];
    char *p=a;
    

    这是合法的,并且与以下内容相同:

    char a[8];
    char *p=NULL;
    p=a;
    

    与:

    char a[8];
    char *p=NULL;
    *p=a;
    

    正如其他人所说,这会产生编译错误或分段错误。

     In the left side of declarations you should read *x as pointer(x) while in
     statements it must be read as value_pointed_by(x). &x on the other hand
     would be pointer_to(x)
    

    【讨论】:

    • 我倾向于将声明 char *p 解读为“*p 是一个字符”,而不是“p 是一个字符 *”,这在早期有助于保持直截了当(也有助于阅读更复杂的声明)。回想起来,如果语法是 &amp;char p 来声明 p 指向 char 的指针,可能会更清楚。
    • 是的,这样会更好,因为它被视为不同的类型。但是,由于 C 是这样,最好声明 char p 而不是 char p,因为前者不适用于后续变量,这使其违反直觉。字符* p,q;是 char* p;字符 q;而不是 char *p,*q;这是你可能会相信的。
    【解决方案5】:

    这是我在学习 C 时使用的一个技巧(今天仍在使用)。

    当您在代码中看到变量前面的 * 时,会自动将其读取为“所指向的内容”。

    所以你应该可以很容易地看到将“p”设置为“a”与将“p 指向的内容”设置为“a”是非常不同的。

    另外,由于 p 应该指向一个 char,将 char p 指向(当前内存位置 0 的“char”,假设 null 为 0)设置为 char 指针 (a) 可能会失败如果幸运的话,在编译时(取决于您的编译器和 lint 设置,它实际上可能会成功。)

    来自评论:在像 f(char c) 这样的函数声明中,我通常会尝试将变量名与其余部分分开 - 所以它将是 f( (char) c )。所以 c 是一个字符 *。和变量定义一模一样。

    而且 & 通常读作“地址”,但这变得更加不确定。举几个我自己读东西的例子。可能会或可能不会帮助您。

    int a[] = {1,2,3}; // I mentally parse this as (int[]) a, so a is an int array.
    int *p;            // p is a pointer to "integers"
    int i;
    p=a;               // p acts exactly as a does now. 
    
    i=*p;          // i is "What is pointed to by" p (1)
    i=p;           // i is some memory address
    i=*a;          // i is what is pointed to by a (1)
    i=p[1];        // Don't forget that * and [] syntax are generally interchangable.
    i=a+1;         // Same as above (2).
    p=&i;          // p is the address of i (it can because it's a pointer)
                   // remember from hs algebra that = generally reads as "is", still works!
    *p=7;          // what is pointed to by p (i) is 7;
    a=*i;          // whoops, can't assign an array.  This is the only difference between
                   // arrays and pointers that you will have to deal with often, so feel
                   // free to use which ever one you are more comfortable with.
    
    char c='a';
    char *  d = &c;// d is a char pointer, and it is the address of c
    char ** e ;    // e is a pointer to a memory location containing
                   // a pointer to a char!
    e=&d;          // gets d's address. a pointer to a pointer gets
                   // the address of a pointer.  Messy but gets the job done
    
    **e=5;         // what is pointed to by what is pointed to by e is 5.
    *e=&'f';       // what is pointed to by e (which is a char * itself, and is still d!)
                   // is set to the address of the memory location holding the value 'f'.
                   // does not change c or e, just d! 
    

    我已经有 10 年没有接触过 c 了,所以其中一些可能有点错误,但它可以帮助我以这种方式大声读出它。

    【讨论】:

    • 当你在函数声明中看到它时你会怎么做?
    • 我建议您也将阅读 * 的方式扩展到声明,以便 int *p 读作“p 指向的内容是 int”,而不是“p是一个int *",有点模糊。
    【解决方案6】:

    不,它们不等价

    如果p = NULL,那么执行*p = a 将给您一个分段错误。

    【讨论】:

      【解决方案7】:
      1. 因为“*p”取消引用指针,这不会使“p”成为“char**”吗?
      2. 这将按预期将“p”指向第一个数组。

      我猜他们不一样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-07-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-10
        • 2016-11-09
        相关资源
        最近更新 更多