指向 char 算术的 C++ 指针
Posted
技术标签:
【中文标题】指向 char 算术的 C++ 指针【英文标题】:C++ pointer to char arithmetic 【发布时间】:2013-06-03 05:29:47 【问题描述】:如果我给一个指针加1,实际加的值是指针指向的类型的大小吗?例如:
int* num[5];
cout << *num << ", " << *(num + 2) << endl;
这将打印存储在 num[1] 和 num[2] 的值, 所以 num + 2 实际上是 num + 2*sizeof(int) 如果我没记错的话。
现在,如果我将一个指向 char 的指针数组初始化为字符串字面量,就像这样:
char* ch[5] =
"Hi",
"There",
"I,m a string literal"
;
这是可以做到的,因为像“hi”这样的字符串文字表示它的第一个字符的地址,在本例中是“h”。现在我的问题是我怎样才能写出类似的东西:
cout << *(ch + 2);
并得到“I,m a string literal”作为输出? 由于指针指向 char,实际上不应该向指针添加 2 (ch + 2*sizeof(char)) 吗?给我输出“那里”?
和cout有关系吗? cout 是否搜索指向值的内存以查看它是否找到 '\0' 将指向值的内容识别为字符串,然后修改指针算术?但是,将 1 添加到指向字符串的 char 的指针将意味着每次添加不同数量的字节(而不是 char 的大小),因为字符串可以是任意大小。还是我完全错了?对不起,我是 C++ 新手,并且是普通编程。
【问题讨论】:
num + 2 实际上是“num + sizeof(int)*2”,或者更准确地说是 (int*) ((char*)num + sizeof(int)*2) 【参考方案1】:和cout有关系吗?
没有:
const char* cstrings[5] =
"Hi",
"There",
"I,m a string literal"
;
const char** x = cstrings + 2;
cout << *x << endl;
。 .
但可能令人困惑的是,当给定一个指向 cstring 的指针时,
int x = 10;
int* pint = &x;
const char* pstr = "hello";
cout << pint << endl << pstr << endl;
--output:--
0x7fff5fbff85c //hexidecimal string representation of an integer
hello
由于指针指向char,
1) 文字字符串作为指针存储在您的数组中。所以数组的类型是指针。
2) 指针是内存中的地址,只是整数。
3) 所以你的指针数组实际上是一个整数数组。
【讨论】:
数组是一个或多个特定类型对象的连续块。 好的,数组名是什么? 数组名是用于在源代码中标识数组的字符序列。您要说的是数组可以隐式转换为指针。不要再说它们是指针,因为它们不是。你让初学者感到困惑。 @Lucas Mezalira,请注意 【参考方案2】:“如果我给一个指针加1,实际加的值就是指针指向右边的类型的大小?”
在 C++ 标准中不能保证指针是指针指向的某个内存的字节数。如果将整数 n
添加到指针,则结果是指向该数组中下一个元素 n
th 的指针:
int iarr[10];
int* pi = iarr; // pi points to iarr[0]
int* pi2 = pi+2; // pi2 points to iarr[2]
当你看的时候你会得到什么,例如。 int repr = (int)pi;
未由 C++ 标准定义。
在最流行的平台/实现上会发生什么
(int)pi2 == ((int)pi) + 2*sizeof(int)
当你有指针数组时,会发生完全相同的事情:
int* piarr[10];
int** ppi = piarr; // ppi points to iarr[0]
int** ppi2 = piarr+2; // ppi2 points to iarr[2]
注意 piarr
的类型是 10 的数组 指向 int 的指针,因此该数组的元素类型为 指向 int 的指针。因此,指向该数组元素的指针的类型为 pointer to pointer to int。
char* ch[5]
是一个 由 5 个指向 char
的指针组成的数组。
"Hello"
等是(窄)字符串文字。 (窄)字符串字面量是一个由 n const char
组成的 数组,其中 n 是字符串的长度加 1(用于终止 \0
字符)。数组可以隐式转换为指向数组第一个元素的指针,这就是这里发生的情况:
char* ch[5] =
"Hi",
"There",
"I,m a string literal"
;
数组ch
包含三个指向字符的指针。由于这些是通过将数组转换为指针获得的,它们中的每一个都指向 char 数组的第一个元素:指针ch[0]
(数组ch
的第一个元素)指向数组“Hi”的第一个元素,ch[1]
指向“There”的第一个元素,依此类推。
请注意,还涉及从const char
到char
的转换,这种转换已被弃用,应该避免。更好的形式是:
char const* ch[5] =
"Hi",
"There",
"I,m a string literal"
;
表达式*(ch + 2)
解释如下:
ch
命名该数组(见上文)
ch + 2
将 ch
从 3 个指向 char 的指针的数组 隐式转换为 指向 char 的指针,一个指向数组 ch
的第一个元素的指针。因此,这个表达式的类型是指向char的指针。
ch + 2
使上一步的指针现在指向第二个下一个元素;它指向ch
的第一个元素,所以它现在指向数组ch
的第三个元素。
*(ch + 2)
最后,*
取消引用指针并“获取”指向的对象。 ch + 2
创建的指针指向数组ch
的第三个元素,因此,该表达式解析为数组ch
的第三个元素。现在表达式的类型是指向字符的指针。
表达式的结果被传递给std::cout::operator<<
。由于表达式的类型是指向字符的指针,cout
将打印该字符串:数组ch
的第三个元素。
【讨论】:
【参考方案3】:在 C 中,字符由数据类型 char
表示。它可以容纳任何 ASCII 字符,范围从 0 到 255。而且它使用单个字节的大小。
然而,字符串由char*
表示,从技术上讲,它是一个字符数组。有区别。 char
与 char*
不同。前者存储单个字符,后者存储对应字符串偏移量的内存方向。
现在,在您的示例中,ch
不是char*
,而是char**
。也就是说,它是 一个字符数组的数组,或者更好的说法是一个字符串数组。如果我们取消引用ch
一次,如*ch
,我们将得到第一个字符串:Hi
。如果我们取消引用它两次,如**ch
,我们将得到第一个字符串的第一个字符:H
。所以,我们可以开始使用指针算法了!
cout << *(ch + 2)
将输出I,m a string literal
cout << **(ch + 1)
将输出T
(第二个字符串的第一个字符)
cout << *(*ch + 1)
将输出i
(第一个字符串的第二个字符)
继续使用这些示例,以更好地了解字符和字符串的输出方式!都是关于指针算术的!
【讨论】:
【参考方案4】:该数组不是存储char
s,而是存储char *
s。因此说ch + 2
将等同于ch + 2*sizeof(char *)
。然后你取消引用它,它指向"I'm a string literal"
。
您最初的示例显示了混乱:
int* num[5];
cout << *num << ", " << *(num + 2) << endl;
这是一个指向 int 的指针数组。因此,*(num + 2)
将是 *(num + 2*sizeof(int *))
,不是 2*sizeof(int)
。让我们用一个小程序来演示一下:
#include <iostream>
int main()
int *num[3];
int x, y, z;
x = 1;
y = 2;
z = 3;
num[0] = &x;
num[1] = &y;
num[2] = &z;
std::cout << *(num + 2) << "\n";
这将打印出一个内存地址(如0x22ff28
),因为它保存的是指针,而不是值。
在 C 和 C++ 中,数组和指针非常相似(许多书籍声称它们完全一样。这并不完全正确,但在很多情况下确实如此)。
您的第一个示例应该是int num[5]
。那么*(num + 2)
(相当于num[2]
)将相当于*(num + 2*sizeof(int)
。希望这能在一定程度上消除您的困惑。
【讨论】:
我忘记将 sizeof(char) 乘以 2,谢谢。但是,你为什么写 2*sizeof(char *) 而不是 2*sizeof(char) ?向指针添加 1 是否意味着将指向值的大小(在本例中为 sizeof(char) )添加到指针?然后 sizeof(ch + 1) 将指向“i”。和 sizeof(ch + 2) 会指向'T'对吗? 是的,但在这种情况下,“指向”的值是char *
。让我编辑我的帖子,我刚刚意识到您对最初的示例感到困惑。以上是关于指向 char 算术的 C++ 指针的主要内容,如果未能解决你的问题,请参考以下文章