在C中混淆指针

时间:2010-01-21 11:46:25

标签: c pointers

我有一个以上的疑问所以请耐心等待。 有人能告诉我为什么这段代码会失败吗?

#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[]char **list之间有什么区别?在什么情况下使用它们都是理想的? 令我困惑的另一件事是argv特别?当我将char **list传递给另一个函数时假设它允许我以argv的方式访问内容,它也失败了。

我意识到过去曾经问过类似的问题,但我似乎无法找到我需要的东西。若有人可以发布相关链接。

5 个答案:

答案 0 :(得分:12)

您应该使用char *list[]={"aaa","bbb","ccc"};代替char **list={"aaa","bbb","ccc"};。您使用char* list[] = {...}; 声明指针数组,但是使用char**将指针传递给指向函数的一个或多个指针。

  • T* x[] =指针数组
  • T** x =指向指针的指针

P.S。响应ejohn:我只能想到一个用于创建指针指针的用法(作为实际声明的变量,而不是作为函数参数或由一元&运算符创建的临时变量):a {{ 3}}。简而言之,句柄是指向指针的指针,其中handl; e由用户拥有,但它指向的指针可以根据操作系统或库的需要进行更改。

在旧的Mac OS中广泛使用了句柄。由于Mac OS是在没有虚拟内存技术的情况下开发的,因此保持堆快速碎片化的唯一方法是在几乎所有内存分配中使用句柄。这让操作系统根据需要移动内存来压缩堆并打开更大,连续的可用内存块。

事实是,这种策略充其量只是“少吸”。有一大堆缺点:

  • 一个常见的错误是程序员取消引用指针的句柄,并将该指针用于多个函数调用。如果这些函数调用中的任何一个移动了内存,则指针有可能变为无效,并且取消引用它会破坏内存并可能导致程序崩溃。这是一个阴险的错误,因为解除引用错误指针不会导致总线错误或分段错误,因为内存本身仍然存在且可访问;它只是不再被您使用的对象使用。
  • 由于这个原因,编译器必须格外小心,并且不能采用一些常见的Subexpression Elimination优化(公共子表达式是对指针的句柄解引用)。
  • 因此,为了确保正确执行,几乎所有通过句柄的访问都需要两次间接访问,而不是一次使用普通旧指针。这可能会影响性能。
  • 操作系统或任何库提供的每个API都必须指定它是否可能“移动内存”。如果你调用了其中一个函数,那么通过句柄获得的所有指针现在都是无效的。没有办法让IDE为您执行此操作或检查您,因为移动内存调用和变为无效的指针可能甚至不在同一源文件中。
  • 性能变得不确定,因为您永远不知道操作系统何时会暂停以压缩您的内存(其中涉及memcpy()工作的批次
  • 多线程变得困难,因为一个线程可以移动内存而另一个线程正在执行或阻塞,使其指针无效。请记住,几乎所有内存分配都必须使用句柄来防止对堆进行分段,因此即使不使用任何Mac OS API,线程仍可能需要通过句柄访问内存。
  • 有函数调用锁定和解锁指针指向的指针,但是,过多的锁定会损害性能并使堆碎片化。

我忘记了可能还有几个。请记住,所有这些缺点仍然比仅使用指针和快速分割堆更加可口,特别是在第一台只有128K RAM的Mac上。这也让我们深入了解为什么Apple完全放弃了这一切并转向BSD,然后他们有机会,一旦他们的整个产品线都有内存管理单元。

答案 1 :(得分:3)

答案 2 :(得分:2)

char ** x指向一个char指针数组,但这可能不是你的编译器在内存中存储{“aaa”,“bbb”,“ccc”}的方式。无论编译器如何存储指针数组,char * x []都将生成正确的代码。

答案 3 :(得分:1)

学习C复杂性的最佳来源是Peter van der Linden的专家C编程(http://www.amazon.co.uk/Expert-Programming-Peter-van-Linden/dp/0131774298)。

这本书的名称具有误导性,因为我认为它很容易被初学者阅读。

答案 4 :(得分:0)

  

“......假设它有事可做   用指针指针的东西,   我不明白。“

How does an array of pointers to pointers work?