在C中使用指针表示法迭代双指针[重复]

Posted

技术标签:

【中文标题】在C中使用指针表示法迭代双指针[重复]【英文标题】:Iterating through a double pointer using pointer notation in C [duplicate] 【发布时间】:2013-03-31 14:35:56 【问题描述】:

如果我有一个指针指向此示例中的变量“bs”之类的指针:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)

    char **bs = "this", "is", "a", "test";

    puts(bs);

    return 0;

puts 语句在屏幕上显示“this”。我将如何让它显示“是”等等。我虽然可以这样做:

puts(bs+1);

向指针变量添加数字实际上有什么作用?它是指向下一个地址,还是考虑指针的类型并使用它所指向的变量的大小来确定下一个变量在内存中的起始位置?

【问题讨论】:

这已经在这里被回答了一千次,在许多教程和文本中。请做一些研究......包括只是尝试一下 它指向下一个地址....下一个地址计算为....baseaddress+ sizeofpointertype(1代表char,2代表int等等..) OTOH,我会忽略所有关于地址计算和 sizeof 的东西。 C,有这个不变量:x[y] == *(x+y)。因此,x+y == &amp;*(x+y) == &amp;x[y]. @MattVaughan 这次你搜索了半个小时(不太可能那么长),但是你学会了如何更好地搜索,所以你的下一个问题需要更少的时间,下一个问题甚至更少,等等。最终,在线查找已发布的解决方案所花费的时间比实际输入您的问题所花费的时间更少。另请注意,没有人想一遍又一遍地回答(或通读)同一个问题(可能有细微的变化)(然后是已经提到的网站混乱)。 如果您查看该线程中的第 5 个答案,它会链接到 ***.com/questions/394767/pointer-arithmetic 并提供更多答案。其中一些答案又链接到具有更多答案的其他线程。另外,请注意 SO 不是 forum,它是一个 repository。当人们提出问题只是为了节省自己的研究时间时,这种区别很重要。 【参考方案1】:

puts 语句在屏幕上显示“this”。

这只是(坏)运气,如果编译器根本不拒绝编译,代码会调用未定义的行为。

clang(默认)对代码产生的警告是

$ clang badpoint.c 
badpoint.c:6:18: warning: incompatible pointer types initializing 'char **' with an
      expression of type 'char [5]' [-Wincompatible-pointer-types]
    char **bs = "this", "is", "a", "test";
                 ^~~~~~
badpoint.c:6:26: warning: excess elements in scalar initializer                          
    char **bs = "this", "is", "a", "test";
                         ^~~~
badpoint.c:8:10: warning: incompatible pointer types passing 'char **' to parameter of   
      type 'const char *'dereference with * [-Wincompatible-pointer-types]
    puts(bs);
         ^~
         *                                                                               
/usr/include/stdio.h:688:32: note: passing argument to parameter '__s' here              
extern int puts (__const char *__s);
                               ^
3 warnings generated.

gcc 为每个多余的初始化器生成一个警告,而 clang 只为三个中的第一个给出一个警告,否则来自 gcc(也是默认情况下)的警告信息量少一些,但相同。

那么发生了什么?

您正在尝试初始化一个标量 (char**),并提供 "this", "is", "a", "test",这是一个用大括号括起来的 initializer-list,其中包含四个 initializer‍s。根据 6.7.9 (11)

标量的初始值设定项应该是一个表达式,可选地用大括号括起来。对象的初始值是表达式的初始值(转换后);应用与简单赋值相同的类型约束和转换,将标量的类型作为其声明类型的非限定版本。

这违反了“应该”的要求,因此会引发未定义的行为。

如果编译器不在那里终止翻译,它可能只是忽略多余的初始化程序 - clang 和 gcc 都这样做 - 并将声明视为它是

char **bs = "this";

这会导致有关从不兼容类型初始化的警告,因为它尝试使用 char[5] 初始化 char**,但根据 6.5.16.1,初始化程序的类型必须与 char** 兼容。

尽管如此,如果编译器成功翻译程序,则很可能导致bs 包含字符串文字中第一个char 的地址(数组"this" 被转换为指向其第一个元素的指针在赋值运算符的右侧)。

然后调用

puts(bs)

将错误类型的指针 (char**) 传递给 puts,这是违反约束并需要来自编译器的诊断消息(并使程序无效)。

但是指针恰好包含正确的地址,并且未定义的行为表现为程序打印"this"

我将如何让它显示“是”等等

通过纠正程序。照原样,字符串"is""a""test" 甚至不会出现在gcc 或clang 生成的目标文件中。

纠正它的一种方法是将声明更改为

char *bs[] = "this", "is", "a", "test";

所以bs 是一个由四个char* 组成的数组,指向四个字符串(各自的第一个元素)。

那你得调整调用puts,解引用或者下标bs

puts(bs[0]);

打印"this";

for(int i = 0; i < 4; ++i) 
    puts(bs[i]);

在不同的行上打印所有四个字符串。

【讨论】:

以上是关于在C中使用指针表示法迭代双指针[重复]的主要内容,如果未能解决你的问题,请参考以下文章

双指针法

C程序:使用双指针更改函数中的字符串

双指针算法

(双指针)Java 求解四数之和

无法使用双指针作为函数参数传递二维数组[重复]

获取双指针指向的对象