65.9K
CodeProject 正在变化。 阅读更多。
Home

使用指针的参考

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.43/5 (11投票s)

2009年1月30日

CPOL

4分钟阅读

viewsIcon

29012

本文旨在帮助解释 C/C++ 如何使用指针。

如何理解 C/C++ 中的指针

典型的终端用户计算机使用的是 x86 系列微处理器,如 Pentium、AMD 或 Intel 的某些原型。这意味着采用了 32 位内存地址方案。由于计算机本质上使用基于 2 的二进制数字系统,这意味着有 2 的 32 次方个可能的内存位置——即 4,294,967,296 (4 GB)。这些内存地址位置不能被物理移动,因此必须进行引用。指针是一种特殊的数据类型,它指向存储着另一个变量地址的地址的位置。当声明一个变量时,编译器会被告知其存在,并由其数据类型定义。当一个变量被初始化时,它会被赋予一个值,该值将根据它所代表的数据类型(整数、字符、浮点小数等)进行存储。尽管 .NET Framework 确实大量使用了指针,但 C/C++ 语言在编程实践中,例如 COM 或 MFC 和 ATL 等 Windows 框架中,也大量使用指针。理解指针有助于学习这些框架,同时也要理解,如果被指向的位置不清楚,就不应该使用指针。本文将使用旧式 C++ 语法(使用标准模板库)以及 Visual C++ Express Edition 上的 Windows C++ 来举例说明指针的使用。同时,本文并非替代 CodeProject 网站上其他更高级的指针文章。

指针允许您在不知道其真实值的情况下操作地址。以下是一些找出指针中存储内容的示例代码。‘\t’ 转义序列字符表示制表符。在此示例中,使用“地址运算符”(&)来显示存储的值的地址。

#include <iostream>
int main()
{
    using namespace std;
    unsigned short_int = 5;
    unsigned long_int = 65535;
    long signed_int = -65535;

    cout << "short_int:\t" << short_int;
    cout << "\tAddress of short int:\t";
    cout << &short_int << endl;
    cout << "long_int:\t" << long_int;
    cout << "\tAddress of long_int:\t" ;
    cout << &long_int << endl;
    cout << "signed_int:\t\t"  << signed_int;
    cout << "\tAddress of signed_int:\t" ;
    cout << &signed_int  << endl;
    return 0;
}

代码块的第一部分显示了这些变量的声明和初始化:一个无符号短整型、一个无符号长整型和一个长整型。如果它是无符号的,那么我们可以假设它是带符号的(在某些情况下,可能带有负号或正号)。这是在使用命令行上的 cl.exe 编译器时的输出。

short_int :            5       Address of short int:   0012FF34
long_int  :            65535   Address of long_int:    0012FF3C
signed_int:           -65535   Address of signed_int:  0012FF38

当变量被声明和初始化(或赋值)时,编译器会负责分配内存并自动为其分配地址。然而,上面的示例仅显示了值及其对应的地址。这并不是非常有用的信息。因此,我们将尝试另一个示例。

include <iostream>
int main()
{

    using namespace std;
    unsigned short int mAge = 32, yAge = 40;
    // a binary pointer
    unsigned short int *pAge = &mAge;
    cout << "mAge:\t" << mAge 
         <<  "\t\tyAge:\t" << yAge << endl;
    cout << "&mAge:\t" << &mAge 
         << "\t&yAge:\t" << &yAge << endl;
    cout << "pAge:\t" << pAge << endl;
    cout << "*pAge:\t" << *pAge << endl;
    cout << "\nReassigning: pAge = &yAge..." 
         << endl << endl;
    pAge = &yAge;
    cout << "mAge:\t" <<  mAge 
         << "\t\tyAge:\t" << yAge << endl;
    cout << "&mage:\t" << &mAge 
         << "\t&yAge:\t" << &yAge << endl;
    cout << "pAge:\t" << pAge << endl;
    cout << "*pAge:\t" << *pAge << endl;
    cout << "\n&pAge:\t" << &pAge << endl;
    return 0;
}

不可否认,这种语法是旧式 C++,有点令人困惑,但当我们查看 Visual C++ 示例时,基本原理应该会变得更清晰。但是,为了简单起见,我们应该避免开发任何类型的 Windows Forms 应用程序。这是输出。

mAge:   32               yAge:   40
&mAge:  0012FF34        &yAge:  0012FF38
pAge:   0012FF34
*pAge:  32

Reassigning: pAge = &yAge...
mAge:   32               yAge:   40
&mAge:  0012FF34        &yAge:  0012FF38
pAge:   0012FF38
*pAge:  40
&pAge:  0012FF3C

虽然 C/C++ 使用指针,但像 Java 这样的其他高级面向对象语言则不使用。Java 开发人员认为指针会产生有缺陷的程序。然而,对象用户(应用程序)访问对象是面向对象的内在特征。对象或模块是一组包含语义上相关的函数,并且永远不能作为一个整体被访问。访问对象是通过间接引用实现的。这是与 COM 客户端和 .NET 对象进行互操作的一些基本原则。COM 可调用包装器 (CCW) 存在于 COM 的非托管平台和 .NET 的托管平台边界。这个 CCW 能够读取元数据并形成类型库。regasm.exe 工具能够为 .NET 程序集创建注册表项,以便它可以显示为 COM 组件。因为我们处理的是对象的使用,所以必须跟踪其生命周期。CCW 能够跟踪 COM 客户端的引用计数,当引用计数达到零时,它就可以将所有涉及的指针映射到该对象的引用,从而允许对其进行垃圾回收。

使用 Visual C++ Express Edition 的示例

只需启动一个新的 C++ 项目,选择 Win32 控制台,然后单击“完成”,而不是单击“空项目”。请务必转到项目的属性,并将“使用 UNICODE 响应文件”设置为“否”,并将“字符集”设置为“使用多字节字符集”。

me.JPG

me1.JPG

// Example_pointer.cpp : Defines the entry point
// for the console application.#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int i = 5;
    printf("  i : %8.X (value)\n", i );
    // the Address of operator '&' tells what the address of i is //
    printf(" &i : %8.X (address)\n", &i);
    // declare a pointer and assign to it the value of the address of i //
    int *p = &i;
    printf ("   p : %8.X (value)\n", p);
    printf("   &p : %8.X (address)\n", &p);
    printf("  *p : %8.X (indirection)\n", *p);
    // use indirection to dereference the variable we//
    // are pointing to and returns the value at that memory location//
    // since contains the address of i, when we use indirection,
    // we get the value of i as a return //
    getc(stdin);
    // the getc function with the standard input parameter
    // passed makes the console remain on your screen.
    return 0;
}

输出如下

  i :        5 (value)
 &i :        2BF774 (address)
  p :        2BF774 (value)
 &p :        2BF768 (address)
 *p :        5 (indirection)

请注意,p 的值与 i 的地址相同。p 的实际地址如果出现在堆栈上稍远的位置,就会显示出来。最重要的是,请注意 *p(解引用)然后再次解引用会返回 i 的值,而不是内存地址。或者 *p = 5

这是最后一个示例的扩展,但增加了对变量 i 的引用。

#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int i = 5;
    printf("  i : %8.X (value)\n", i );
    printf(" &i : %8.X (address)\n", &i); 
    int *p = &i;
    printf ("   p : %8.X (value)\n", p);
    printf("   &p : %8.X (address)\n", &p);
    printf("  *p : %8.X (indirection)\n", *p); 

    // since contains the address of i, when we use indirection,
    // we get the value of i as a return //

    int &r = i; // a reference to i or an alias for i
    printf("  r : %8.X (value)\n", r);
    // printf the address of r
    printf (" &r : %8.X (address)\n", &r);
    int **pp = &p;

    printf(" pp : %8.X (value)\n",  pp);
    printf(" &pp : %8.X (address)\n", &p);
    printf(" *pp : %8.X (indirection)\n", *pp);
    printf(" **pp : %8.X (double indirection)\n", **pp);
    getc(stdin);
    return 0;
}

输出如下

  i :      5 (value)
 &i :      1DFDDC (address)
  p :      1DFDDC (value)    // p has the value of the address of i
 &p :      1DFDD0 (address)  // the address of p is a short distance on the stack
 *p :      5 (indirection)   // the binary pointer for indirection returns the value of i
  r :      5 (value)         // r as a reference is just an alias for i.
 &r :      1DFDDC (address)  // the address of r is thus the same as the address of i
 pp :      1DFDD0 (value)
&pp :      1DFDD0 (address)
*pp :      1DFDDC (indirection)   // the indirection redirect the original indirection
                                  // to return the address of i.
**pp:      5 (double indirection) // the double indirection dereferences the above
                                  // to return the value of i.

指针提供了通过间接引用访问数据的强大方法。每个变量都有一个地址,可以使用地址运算符(&)获得。该地址可以存储在指针中。

© . All rights reserved.