如何理解字符 * ch= "123"?
how to understand char * ch="123"?
我应该如何理解char * ch="123"
?
'1'
是一个char
,所以我可以使用:
char x = '1';
char *pt = &x;
但是我如何理解char *pt="123"
?为什么char *pt
可以指向字符串?
pt
的值是"123"
的第一个地址值吗?如果是这样,我如何获取 pt
指向的字符串的长度?
这实际上是一个非常好的问题,它是C语言中几个奇怪问题的结果:
1:指向字符(char*
(的指针当然也可以指向字符数组中的特定字符。这就是指针算法所依赖的:
// create an array of three chars
char arr[3] = { 'a', 'b', 'c'};
// point to the first char in the array
char* ptr = &arr[0]
// point to the third char in the array
char* ptr = &arr[2]
2:字符串文字("foo"
(实际上不是一个字符串,而只是一个字符数组,后跟一个空字节。(所以"foo"
实际上等价于数组{'f', 'o', 'o', ' '}
(
3:在 C 中,数组"衰减"为指向第一个元素的指针。(这就是为什么许多人错误地说"C 中的数组和指针之间没有区别"(。也就是说,当您尝试将数组分配给指针对象时,它会将指针设置为指向数组的第一个元素。所以给定上面声明的数组arr
,你可以做char* ptr = arr
,它的意思与char* ptr = &arr[0]
相同。
4:在所有其他情况下,像这样的语法会使指针指向一个右值(松散地说,一个临时对象,你不能接受它的地址(,这通常是非法的。(你不能做int* ptr = &42
(。但是当你定义字符串文字(如 "foo"
(时,它不会创建右值。相反,它会创建具有静态存储的 char 数组。您正在创建一个静态对象,该对象是在加载程序时创建的,当然指针可以安全地指向该对象。
5:字符串文字实际上需要标记为const
(因为它们是静态和只读的(,但由于早期版本的 C 没有 const
关键字,因此您可以省略const
说明符(至少在 C++11 之前(,以避免破坏旧代码(但您仍然必须将变量视为只读(。
所以char* ch = "123"
真正的意思是:
- 将 char 数组
{'1', '2', '3', ' '}
写入可执行文件的静态部分(以便在将程序加载到内存中时,在内存的只读部分中创建此变量( - 执行此行代码时,创建一个指向此数组的第一个元素的指针
作为一个额外的有趣的事实,这与 char ch[] = "123";
不同,而是意味着
- 将 char 数组
{'1', '2', '3', ' '}
写入可执行文件的静态部分(以便在将程序加载到内存中时,在内存的只读部分中创建此变量( - 执行此行代码时,在堆栈上创建一个数组,其中包含此静态分配数组的副本。
char* ptr = "123";
兼容并且几乎等同于char ptr[] = { '1', '2', '3', ' ' };
(见 http://ideone.com/rFOk3R(。
在 C 中,指针可以指向一个值或一个连续值数组。C++继承了这一点。所以字符串只是一个以' '
结尾的字符数组(char
(。指向char
的指针可以指向char
数组。
长度由开头和结尾' '
之间的字符数给出。C 的示例strlen
给出字符串的长度:
size_t strlen(const char * str)
{
const char *s;
for (s = str; *s; ++s) {}
return(s - str);
}
是的,如果最后没有' '
,它会失败得很惨。
文本是 N 个const char
数组,其中 N 是文本的长度,包括隐式 NUL 终止符。它具有静态存储持续时间,并且它的实现定义了存储位置。从这里开始,它与普通数组相同 - 它衰减到指向其第一个字符的指针 - 这是一个const char*
.你在那里拥有的东西在C++中是不合法的(自 C++11 标准开始以来就不再合法了(,它应该是const char* ch = "123";
.
您可以使用运算符获取文本sizeof
长度。但是,一旦它衰减到指针,您需要遍历它并找到终止符(这就是strlen
函数的作用(。
因此,使用const char* ch;
,您将获得指向常量字符类型的指针,该指针可以指向单个字符或字符数组的开头(或开头和结尾之间的任何位置(。数组可以是动态的、自动的或静态分配的,可以是可变的,也可以是可变的。
在类似char ch[] = "text";
的东西中,你有一个字符数组。这是普通数组初始值设定项的合成糖(如char ch[] = {'t','e','x','t',' '};
但请注意,文本仍将在程序开始时加载(。这里发生的事情是:
- 分配具有自动存储持续时间的阵列
- 它的大小是由编译器从文字的大小推导 出来的
- 文本的内容被复制到数组中
因此,您有一个可以随意使用的存储区域(与文字不同,文字不得写入(。
C 中没有字符串,但有指向字符的指针。 *pt
确实不是指向字符串,而是指向单个字符('1'
(。但是,某些函数将char*
作为参数,假设其参数指向的地址后面的地址上的字节设置为0
,如果他们不对其进行操作。
在您的示例中,如果您尝试对需要"null 终止字符串"的函数使用pt
(基本上,它期望它在应该停止处理数据时会遇到值为 0
的字节(,您将遇到分段错误,因为x='1'
x
提供了1
字符的 ascii 值, 但仅此而已,char* pt="123"
给出了 pt 1
地址的值,但也将包含 ASCII 值的字节放入该内存中 1
、 2
3
后跟一个值为 0
(零(的字节。
因此,内存(在 8 位机器中(可能如下所示:
地址 = 内容(0x31
是字符 1(一(的 ASCII 代码(
0xa0 = 0x31
0xa1 = 0x32
0xa2 = 0x33
0xa3 = 0x00
假设你在同一台机器char* otherString = malloc(4)
,假设malloc
返回一个值 0xb0
,现在是 otherString
的值,并且我们想将我们的 "pt
"(其值为 0xa0
(复制到 otherString
中,strcpy
调用将如下所示:
strcpy( otherString, pt );
同
strcpy( 0xb0, 0x0a );
然后strcpy
会获取地址0xa0
的值并将其复制到0xb0
中,它会将指向"pt
"的指针递增到0xa1
,检查0xa1
是否为零,如果不是零,它将递增指向"otherString
"的指针,并将0xa1
复制到0xb1
中,依此类推, 在它被0xa3
"pt
"指针之前,在这种情况下,它将返回,因为它检测到"字符串"的末尾已经到达。
这是有原因的,而不是100%如何进行,它可以以许多不同的方式实现。
这是一条 http://fossies.org/dox/glibc-2.18/strcpy_8c_source.html
指向数组的指针?
指针仅指向一个内存地址。指针指向数组的短语仅在松散的意义上使用---指针不能真正同时存储多个地址。
在您的示例中,char *ch="123"
,指针ch
实际上只指向第一个字节。您可以编写如下代码,这将是非常有意义的:
char *ch = new char [1024];
sprintf (ch, "Hello");
delete [] ch;
char x = '1';
ch = &x;
请注意,使用指针ch
指向new char [1024]
行分配的内存以及变量x
的地址,同时仍然是相同的指针类型。
C 样式字符串以空值结尾
C中的字符串曾经以null结尾,即在字符串的末尾添加一个特殊的' '
,并假定所有基于char *
的函数(如strlen
和printf
(都存在,这样,你可以通过从第一个字节开始来确定字符串的长度,直到找到包含0x00
的字节。
strlen
样式函数的详细示例实现将是
int my_strlen (const char *startAddress)
{
int count = 0;
char *ptr = startAddress;
while (*ptr != 0)
{
++count;
++ptr;
}
return count;
}
char* pt = "123"; does two things:
1. 在 ROM 中创建字符串文字"123"(这通常在 .text 部分( 2. 创建一个char*
,该被分配字符串所在的内存位置的开头。
由于此操作like pt[1] = '2';
是非法的,因为您将尝试写入ROM内存。
但是您可以将指针分配给其他内存位置,而不会出现任何问题。
- 理解boost::asio-async_read在无需读取内容时的行为
- 如何理解C++标准N3337中的expr.const.cast子句8
- C++,我收到一个无法理解的编译器错误
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 理解c++中的引用
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- Python中的for循环与C++有何不同
- 通过实例理解std::move及其目的
- 无法理解此 return 语句的功能,没有它就会发生运行时错误
- 试图理解类对象的行为
- 难以理解某些人解决IOI问题的源代码
- 有人能帮我理解这个c++代码吗
- 理解循环C++中的循环
- 理解这行C++指针代码
- 理解GCC中的std::pow实现
- 正在理解智能指针,但出现错误:未分配正在释放的指针
- 此测试()中发生了什么意外过程?为什么总是覆盖 ch[0 1 2..]?
- 如何理解新的运算符重载?
- 为什么理解这个递归示例如此难以转化为直觉?
- 如何理解字符 * ch= "123"?