我是自学c ++,我得到了指针的工作方式。但我正在使用的文档是非常文字的,并且示例并没有真正说明为何或何时使用指针。一些现实世界的例子可以帮助我保留知识。
答案 0 :(得分:9)
当您希望对象存在的时间长于当前堆栈时,可以使用指针。您也可以使用它们来避免将对象复制到容器中。
// TODO: Remember to call DeleteObjects() when you're done here!!
std::vector<MyObject*> Objects;
void Test()
{
MyObject *const pObject = new MyObject();
Objects.push_back(pObject);
}
void DeleteObjects()
{
std::vector<MyObject*>::iterator it = Objects.begin(), itEnd = Objects.end();
for (; it != itEnd; ++it)
{
delete *it;
}
Objects.clear();
}
答案 1 :(得分:3)
这不是一个容易回答问题的简单问题,而且我确信有很多资源在讨论指针。基本上,无论何时你想使用间接(甚至可能是递归),你都需要指针。
例如说一个二叉树数据结构,其中每个节点都有指向它的左右子树的指针,其中任何一个可能指向0
(或NULL,表示无效指针)以表示没有子树那里。这个结构可能看起来像这样(不是很C ++ - y,但这是一个不同的故事)
struct TreeNode
{
TreeNode* left;
TreeNode* right;
}
在这种情况下你不能使用任何指针,因为它是一个无限大的结构。
答案 2 :(得分:1)
答案 3 :(得分:1)
当您需要一个函数来返回多个变量时,指针很有用。例如,考虑一下您在杂货店购物。每个产品都有名称和价格。名称将是一个字符串,价格为双倍。如果有一个名为“buy”的函数,并且您想要返回该项的名称和价格,则可能需要使用指针。
答案 4 :(得分:1)
这不是C ++的问题,而是C问题。对于初学者,我很乐意推荐这本书Understanding Pointers in C
答案 5 :(得分:1)
指针的一个简单示例是链接列表。有关wikipedia的更多信息。
答案 6 :(得分:0)
void print_values(int* iptr, int size)
{
int i;
for (i=0; i < size; i++)
{
printf("%d ", *(iptr++));
}
printf("\n");
}
int main()
{
int table[256];
memset(table, 0, sizeof(table));
print_values(table, sizeof(table)/sizeof(int));
}
或者像一组函数(例子):
#define ___FUNC_B { func_1, func_2, func3 }
void ( __closure __fastcall * __FUNC_B [__FUNC_MAX] )( TObject* ) = ___FUNC_B;
按指针使用对象在很多情况下更好:
CClass *ptr = new CClass();
/* something */
delete ptr;
如果您有许多对象,并且您必须以某种方式(例如,排序)获取它,您可以使用指针来指向非对象的对象:
vector <CClass*> Vptr;
for (i=0; i < 100; i++)
{
Vptr.push_back(new CClass());
}
sort(Vptr.begin(), Vptr.end(), __cmp_func);
/* something */
while (!Vptr.empty())
{
delete *(Vptr.begin());
Vptr.erase(Vptr.begin());
}
用C语言进行动态内存分配:
char *memory = (char*) malloc(1024);
if (memory == NULL)
{
exit(1);
}
/* you have alocated 1KB in memory */
memory = (char*) realloc(2048);
if (memory == NULL)
{
exit(1);
}
/* you have alocated 2KB in memory */
free(memory);
/* you have nothing */
答案 7 :(得分:0)
是c ++的一个示例用法 指针?
指针解决了以下问题:
避免复制大块内存。至少在C语言中,在C ++中,首选方法是使用引用。如果你愿意,你仍然可以使用指针。
在运行时分配内存。当您不知道编译将使用多少内存时,需要这样做。
记住延迟调用(和回调)的(成员)函数的地址。
分配超出当前范围的内存(在范围完成后仍然分配)。
在多个实体(多个对象,多个线程等)之间共享对象。这意味着您可以传递对象的地址,使用它的所有实体都将访问相同的数据,而不是相同的副本。
有时指针也用作句柄。也就是说,如果您希望允许客户端代码唯一地标识数据块而不关心(或知道)数据是什么,则将数据的地址(指针)转换为int /某些其他类型并将其传递为一个手柄。这通常在提供客户端代码句柄的API中找到,但不允许客户端代码访问实际数据(请参阅使用WinAPI的HANDLE,HWND等 - 这些是内部实现中的指针,但您不知道 - 或者关心 - 为了使用它,实际数据是什么。)
答案 8 :(得分:0)
好的,我看到了很多可怕的反应,我觉得自己有义务再增加一个。
首先要做的事情是:我们在这里谈论C ++。如此多的C使用完全失效。
指针的可怕用途
你应该学习RAII :这个例子在面对异常时是完全不安全的
// BAD
void func(size_t n)
{
int* array = new int[n];
// .. use array
delete[] array;
}
// GOOD
void func(size_t n)
{
std::vector<int> array(n, 0);
// .. use array
}
经验法则:如果你看到delete
,那你做错了。如果你看到new
,也有可能因为参数转发问题而不是真的。
尽可能使用参考
// BAD: Contract: do not pass NULL
void func(int* i);
// GOOD
void func(int& i);
每当传递NULL
没有意义(并且您不需要重新绑定)时,请使用普通值或(const)引用而不是指针。
指针的良好用途:
混叠
void printSorted(std::vector<BigType> const& values)
{
std::vector<BigType*> references = from(values);
std::sort(references.begin(), references.end(), ByPointer());
std::transform(references.begin(), references.end(),
std::ostream_iterator<BigType>(std::cout, " "),
Dereference());
}
可选结果
Object* find(Key const& key);
这相当于:
boost::optional<Object&> find(Key const& key);
但不那么冗长。
克隆方法
使用裸指针作为clone
方法的返回类型是由Boost Cloneable概念强制执行的:
struct Base
{
virtual ~Base() {}
virtual Base* clone() const = 0;
};
有一个合理的理由:利用协变返回类型来重载虚拟方法。这允许我们写:
struct Derived: Base
{
virtual Derived* clone() const { return new Derived(*this); }
};
因此,当从Derived const&
克隆时,充分利用我们知道返回的内容至少 a Derived
。
遗憾的是程序员需要处理已分配的内存,因此必须与Smart Containers一起使用:
std::unique_ptr<Base> u = derived.clone();
答案 9 :(得分:-1)
指针可以被视为一个简单的变量,但不是保存值,而是将地址保存到存储值的内存位置。
将记忆视为一个抽屉,在每个抽屉中你可以设置一个值,以便更容易找到值,你可以抽出几个抽屉。因此,记忆的位置将是抽屉,而块将是完整的记忆。
因此,当您创建指针时,例如:
int* drawer = 0;
你指的是标有数字0并且包含整数值的抽屉,现在你可能会想,好吧,但是,我怎样才能得到这个值?嗯,这很简单:
int value = *drawer;
以同样的方式,您可以在该抽屉上存储新值(内存地址):
*drawer = 15;
现在很有趣,抽屉柜很神奇,抽屉可以把你带到街区的另一个抽屉里,如果我们用相同的数字标记它们,那么一个存储的价值在另一个中是相同的:< / p>
int* drawer = 0;
int* drawer_copy = drawer;
*drawer = 15;
会发生什么? “drawer_copy”,将地址0称为“抽屉”,允许您访问整数值15。
我们还可以保存正常变量的地址,我们使用“&amp;”获得该地址的前缀:
int value = 15;
int* drawer = &value;
如果我们现在这样做:
value = 5;
“*抽屉”将返回5。
正如您所看到的,指针允许用户对内存进行更多控制并永久保留内存,一旦声明了指针,就可以保留地址并随时访问它。 :)