char 和 char*(指针)
Posted
技术标签:
【中文标题】char 和 char*(指针)【英文标题】:char and char* (pointer) 【发布时间】:2012-10-04 08:02:00 【问题描述】:我想了解指针是如何工作的,所以我创建了这个小程序。首先,我创建了一个指向 char 的 p 指针。
第一个问题到此为止。如果我创建一个指针,它的值是一个内存地址(如果我将它指向一个非指针对象),但这次在我的示例中是“哈哈”。为什么它在 char* 中以这种方式工作?以及如何使用 cin >> p 为其增加价值?
我的第二个问题是,我创建了一个 q char,它在我创建它时具有 *p 指针的值。但是它的值和地址也是“h”,但为什么呢?一定是这个char对象的内存地址!这是毫无意义的 :D (mingw - gcc)
#include <iostream>
int main()
/* char *p;
cin >> p; //forexample: haha */
char * p = "haha";
char q = *p;
std::cout << "&q = " << &q << std::endl; //&q = h
std::cout << "q = " << q << std::endl; //q = h
return 0;
更多:如果我先用 char a[100] 分配内存;字符 *p=a;然后&q = h»ŢĹ,所以“h”有些乱。但它应该是一个内存地址!我的问题是,为什么不解决呢?
【问题讨论】:
那不安全。p
没有任何内存可供您输入。
【参考方案1】:
将char* p;
视为内存中的地址。你没有初始化这个指针,所以它不指向任何东西,你不能使用它。
始终保持安全: 要么将指针初始化为零:
char *p = 0; // nullptr in C++11
或初始化为一些自动的
void foo()
char a[100];
char *p = a;
或全局内存:
char a[100];
void foo()
char *p = a;
或获取动态内存:
char* p = new char [100];
然后你可以使用p(如果不是NULL)来读取数据并从p中读取...
感谢您对operator >> (std::istream&, char* p)
的误解。该操作员期望 p
指向一些内存(自动、全局、动态 - 无论如何) - 它不会自行分配内存。它只是从输入流中读取字符直到空白并将其复制到p
指向的内存中 - 但p
必须已经指向一些内存。
用于获取char q;
的地址。当然你可以取q
的地址:&q
,它的类型是char* p
。但是&q
与p
不同,这个q=*p
只是将p
指向的第一个字符复制到q
,它不能改变q
的地址——它的地址是不可改变的。对于cout << &q
- operator << (ostream&, char* p)
期望 p
指向以 NULL 结尾的字符串 - 并且 &q
指向包含 "H"
的内存,但没有人知道这个字符之后的内容 - 所以你会在屏幕上看到一些垃圾。使用cout << q
打印单个字符。
【讨论】:
那么,你说cin不分配内存,那我的“哈哈”呢?指针如何包含整个字符串? q 是一个简单的 char 变量,所以它可以包含 p 的任何字符,而且我没有分配我的“哈哈”文本,所以这就是为什么我的“h”没有内存地址?很清楚,但是我有一个问题:当我将字符复制到 q (char q = *p) 时,它实际上并不是在复制,它只是指向未分配的数据?所以问题无处不在,我的哈哈文本没有分配,所以我不能从中获得任何地址? ok,我用int创建了一个程序,int已经分配好了,我可以cout了p = a; cin >> (char *)p; cout )p); " 因为您没有为p
分配任何值,甚至0
- 然后它指向某个随机地址。您将“哈哈”复制到程序中的一些随机存储器中——它可能导致任何事情,这是未定义的行为——它甚至可能导致向你的老板发送一封电子邮件,说你有更好的工作——但这种随机存储器也可能发生未使用 - 因此您的程序似乎工作正常。
最后一个例子:int a[10];
- 假设a
的内存地址是0x123。 int p = a;
- 你将地址转换为 int - 所以 p == 0x123
作为值。 (char*)p
反向转换 - 所以你的程序认为 0x123 是 char 数组的开始。所以int[10]
等价于char[10*sizeof(int)]
...所以你有记忆,一切正常。
是的,但在我的示例中 p 等于内存地址。我用 a[100] 创建了你的例子,p 是“哈哈”,不等于内存地址,但应该是!【参考方案2】:
你应该有类似的东西:
#include <iostream>
using namespace std;
在程序的顶部。或者可以省略using
并参考std::cin
和std::cout
。
int main()
char *p;
p
是一个指针,但你还没有初始化它,所以它可以指向任何地方,也可以不指向任何地方。你需要初始化它,例如:
p = new char[100];
...
cin >> p; //forexample: haha
这没关系如果你已经初始化p
指向某个地方——除了如果你输入太多数据,你可能会溢出它指向的缓冲区。对于这样一个简单的测试程序来说没问题,但在实践中,您需要采取措施来避免它。
char q = *p;
cout << "&q = " << &q << endl; //&q = h
&q
的类型为char*
,是一个指向char
的指针。将char*
值发送到cout
不会打印指针的值(内存地址);它打印它指向的字符串。 (虽然我自己运行它时得到了一些奇怪的结果;我可能会遗漏一些东西。)如果您想查看指针值,请将其转换为 void*
:
count << "&q = " << (void*)&q << endl;
(或者您可以使用特定于 C++ 的强制转换之一;我不确定哪个最好。)
cout << "q = " << q << endl; //q = h
这里q
只是一个char
,所以这会将其值打印为一个字符:h
。
return 0;
【讨论】:
是的,在我的代码中,我采用了前两行,但很明显,所以我没有放在这里。我明白了,但是 cout 【参考方案3】:首先要学习并永远记住指针是确保为它们分配内存,否则您的程序将无法正常运行。
您的代码实际上应该修改如下以分配内存,以便“cin”可以将用户输入写入分配的内存:
int main()
char *p = new char[1024]; // allocate memory so cin
cin >> p; //forexample: haha
char q = *p;
cout << "&q = " << &q << endl;
cout << "q = " << q << endl;
return 0;
现在,字符指针是一个变量,指向内存中保存一组字符的位置(不一定是一个字符,可能不止一个字符,也可能没有,如特殊值 null 的情况),而字符变量实际上是持有一个字符(不是一组字符)。
处理指针时的基本运算符是 &(address of) 和 *(value at)。 & 检索变量的地址,所以如果我们有 [char q;] 那么 [&q] 将是一个字符指针。另一方面,* 检索给定指针的值,所以如果我们有 [char *p;] 那么 [*p] 将是内存中 p 指向的字符。
现在回到你的例子,cmets inline 用于说明
int main()
// allocate a place of 1024 character in memory
// and let p points to that place
char *p = new char[1024];
// call cin to read input from the user and save
// it in memory at the location pointed to by p
// NOTE: cin would put an extra NULL character
// at the end to terminate the string
cin >> p; //forexample: haha
// Now p would be pointing to a piece of memory like this
// [h] [a] [h] [a] [\0]
// use the value at operator to de-reference the pointer
// p, the result would be a single character which
// will be the first character in memory p is pointing at
char q = *p;
// printing the value of (the address of q)
// Note you have a problem here as cout will
// be handling the memory starting at the address
// of q as a string while it is not, so you
// will get a string starting with "h" and followed
// by whatever is there in memory by the time of execution
cout << "&q = " << &q << endl;
// printing the value of the character q
cout << "q = " << q << endl;
return 0;
希望对你有帮助
【讨论】:
是的,很明显,如果我将位置分配给 p,那么它会将“h 和一些混乱”写入 &q,但如果我不分配位置给 p,那么它只会写入“h”,和 *p 有什么区别。所以 q=&q? :D 但我认为 PiotrNycz 是对的,这是因为“哈哈”没有分配,所以它没有内存地址,所以 &q(即 p)不能指向任何地方,但是为什么它在“h”之后停止了“然后呢? @Iburidu 您的机器/编译器上发生的特定情况不是一般情况。在未分配的内存空间中存储数据的结果是不可预测的。在您的情况下,内存已经充满了零,因此打印以 &q 开头的字符串只是偶然正确打印出“h”,仅此而已。 好的,我是通过添加char a[100]分配的;诠释* p = a;但是为什么 p == "haha",如果它应该是内存地址 (&a[0])? @Iburidu 数组在 C++ 中被实现为指针,因此大多数时候您可以互换使用数组和指针。例如: int *p = new int[100];那么你可以做 p[0]=1; p[1]=50; ...等 @Iburidu 回到你的例子:cout 将打印出字符串“haha”,因为它会注意到你正在尝试打印一个 char* ...如果你想打印地址,你可以转换它到(void *)
或使用声明printf("%p", p);
【参考方案4】:
字符串 literate 将存储在 .rdata 部分中,该部分将是只读的,因此使用 std cin 读取它会导致程序崩溃
第二件事,当你写这个时:
char *p = "some text";
然后指针 p 指向一个已分配和只读的内存,因为 rdata 部分肯定会由 windows 加载程序分配和准备,但正如我所说的 .rdata 不能修改
那么当你写这个时:
char q = *p;
您只需将 q 分配给 p 中的第一个字符,因为 * 返回指针当前指向的值,所以如果您尝试这样做:
++p;
q = *p;
q 将持有 'a' 而不是 'h' 因为指针是一个指向从第一个字符开始的一些字符的地址,因此增加一个它将使指针指向第二个字符并且 q 将保持这个值
【讨论】:
【参考方案5】:更好的方法是:
int arraySize;
cin>>arraySize;
char *a=new char[arraySize];
cin >> a;
【讨论】:
以上是关于char 和 char*(指针)的主要内容,如果未能解决你的问题,请参考以下文章
数组名相当于一个指针,哪数组指针char *p[],不就变成一个二级指针?
指向 char 指针数组的指针与指向 char 指针的指针(或 char** argv 与 char* (*argv)[])