我有不止一个疑问,所以请耐心等待。
有人能告诉我为什么这段代码失败吗?
#include<stdio.h>
void main(int argc,char **argv) /*assume program called with arguments aaa bbb ccc*/
{
char **list={"aaa","bbb","ccc"};
printf("%s",argv[1]);/*prints aaa*/
printf("%s",list[1]); /*fails*/
}
我认为它与指针指向指针的东西有关,我不太明白。所以我尝试了:
#include<stdio.h>
void main()
{
char **list={"aaa","bbb","ccc"};
char *ptr;
ptr=list;
printf("%s",ptr);/*this prints the first string aaa*/
/* My second question is how do i increment the value
of ptr so that it points to the second string bbb*/
}
有什么区别char *list[]
and char **list
两者都适合在什么情况下使用?
另一件让我困惑的事情是 argv 很特别吗?当我经过时char **list
到另一个函数,假设它可以让我以我可以的方式访问内容argv
,也失败了。
我意识到过去曾被问过类似的问题,但我似乎找不到我需要的东西。如果是的话,有人可以发布相关链接。
你应该使用char *list[]={"aaa","bbb","ccc"};
代替char **list={"aaa","bbb","ccc"};
。你用char* list[] = {...};
to declare指针数组,但你使用char**
将一个指针传递给一个或多个指向函数的指针。
-
T* x[]
= 指针数组
-
T** x
= 指向指针的指针
附:回应 ejohn:我能想到的只有一种用途来创建指向指针的指针(作为实际声明的变量,而不是作为函数参数或由一元创建的临时变量)&
运算符):一个handle http://en.wikipedia.org/wiki/Handle_(computing)。简而言之,句柄是指向指针的指针,其中句柄由用户拥有,但它指向的指针可以根据操作系统或库的需要进行更改。
句柄在旧的 Mac OS 中被广泛使用。由于 Mac OS 是在没有虚拟内存技术的情况下开发的,因此防止堆快速碎片化的唯一方法是在几乎所有内存分配中使用句柄。这使得操作系统可以根据需要移动内存以压缩堆并打开更大的、连续的可用内存块。
事实是,这种策略充其量只是“吸得更少”。有很多缺点:
- 一个常见的错误是程序员取消对指针句柄的引用,并使用该指针进行多个函数调用。如果这些函数调用中的任何一个移动了内存,则指针有可能变得无效,并且取消引用它会损坏内存并可能导致程序崩溃。这是一个阴险的错误,因为取消引用坏指针不会导致总线错误或分段错误,因为内存本身仍然存在并且可访问;它只是不再被您正在使用的对象使用。
- 因此,编译器必须格外小心,并且无法进行某些公共子表达式消除优化(公共子表达式是对指针的句柄取消引用)。
- 因此,为了确保正确执行,几乎所有通过句柄的访问都需要两次间接访问,而不是使用普通的旧指针进行访问。这可能会损害性能。
- 操作系统或任何库提供的每个 API 都必须指定它是否可以“移动内存”。如果您调用这些函数之一,则通过句柄获得的所有指针现在都无效。没有办法让 IDE 为您执行此操作或检查您,因为移动内存调用和指针变得无效甚至可能不在同一个源文件中。
- 性能变得不确定,因为您永远不知道操作系统何时会暂停以压缩内存(这涉及到lot of
memcpy()
work).
- 多线程变得很困难,因为一个线程可以在另一个线程正在执行或阻塞时移动内存,从而使其指针无效。请记住,几乎所有内存分配都必须使用句柄,以防止堆碎片,因此即使线程不使用任何 Mac OS API,它们仍然可能需要通过句柄访问内存。
- 有一些函数调用用于锁定和解锁句柄指向的指针,但是,过多的锁定会损害性能并使堆碎片化。
可能还有几个我忘记了。请记住,所有这些缺点仍然比仅使用指针和快速碎片化堆更容易接受,尤其是在只有 128K RAM 的第一代 Mac 上。这也让我们了解了为什么苹果非常乐意放弃所有这些并转向 BSD,然后他们有机会,一旦他们的整个产品线都有内存管理单元。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)