我应该如何理解char * ch="123"
?
'1'
是char
,因此我可以使用:
char x = '1';
char *pt = &x;
但我如何理解char *pt="123"
?为什么char *pt
指向字符串?
pt
的值是"123"
的第一个地址值吗?如果是这样,我如何得到pt
指向的字符串的长度?
答案 0 :(得分:35)
这实际上是一个非常好的问题,它是C语言中几个奇怪的结果:
1 :指向char(char*
)的指针当然也可以指向chars数组中的特定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', '\0'}
)
3 :在C中,数组“衰减”成指向第一个元素的指针。 (这就是为什么许多人错误地说“C中的数组和指针之间没有区别”)。也就是说,当您尝试将数组分配给指针对象时,它会将指针设置为指向数组的第一个元素。因此,给定上面声明的数组arr
,您可以执行char* ptr = arr
,它与char* ptr = &arr[0]
相同。
4 :在所有其他情况下,这样的语法会使指针指向一个右值(松散地说,一个临时对象,你不能拿地址),这通常是非法。 (你不能int* ptr = &42
)。但是当您定义字符串文字(例如"foo"
)时,它不会创建右值。相反,它使用静态存储创建char数组。你正在创建一个静态对象,它是在加载程序时创建的,当然指针可以安全地指向那个。
5 :字符串文字实际上需要标记为const
(因为它们是静态和只读的),但因为早期版本的C没有{{1关键字,你可以省略const
说明符(至少在C ++ 11之前),以避免破坏旧代码(但你仍然必须将变量视为只读)。
所以const
的确意味着:
char* ch = "123"
写入可执行文件的静态部分(这样当程序加载到内存中时,此变量就会在内存的只读部分中创建)作为奖励有趣的事实,这与{'1', '2', '3', '\0'}
不同,后者意味着
char ch[] = "123";
写入可执行文件的静态部分(这样当程序加载到内存中时,此变量就会在内存的只读部分中创建)答案 1 :(得分:7)
char* ptr = "123";
兼容,几乎等同于char ptr[] = { '1', '2', '3', '\0' };
(请参阅http://ideone.com/rFOk3R)。
在C中,指针可以指向一个值或一个连续值数组。 C ++继承了这一点。
所以字符串只是一个以char
结尾的字符数组('\0'
)。指向char
的指针可以指向char
的数组。
长度由开头和终端'\0'
之间的字符数给出。 C strlen
的例子给出了字符串的长度:
size_t strlen(const char * str)
{
const char *s;
for (s = str; *s; ++s) {}
return(s - str);
}
是的,如果最后没有'\0'
,它就会失败。
答案 2 :(得分:5)
字符串文字是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','\0'};
中所示,但请注意,文字仍将在程序开头加载)。这里有什么:
因此,您可以随意使用存储区域(与文字不同,不得写入)。
答案 3 :(得分:3)
指针只指向一个内存地址。指针指向数组的短语仅用于松散的意义---指针不能同时存储多个地址。
在您的示例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中的字符串过去是空终止的,即在字符串的末尾添加了一个特殊的'\0'
,并假定它适用于所有基于char *
的函数(例如strlen
}和printf
)这样,您可以通过从第一个字节开始确定字符串的长度,并继续直到找到包含0x00
的字节。
strlen
样式函数的详细示例实现将是
int my_strlen (const char *startAddress)
{
int count = 0;
char *ptr = startAddress;
while (*ptr != 0)
{
++count;
++ptr;
}
return count;
}
答案 4 :(得分:3)
C中没有字符串,但有指向字符的指针。
*pt
确实没有指向字符串,而是指向单个字符('1'
)。
但是,某些函数将char*
视为参数,假设其参数所指向的地址后面的地址上的字节如果不对其进行操作则设置为0
。
在您的示例中,如果您尝试在需要“空终止字符串”的函数上使用pt
(基本上,它应该会遇到值为0
的字节停止处理数据)您将遇到分段错误,因为x='1'
给x
1
字符的ascii值,但仅此而已,而char* pt="123"
给pt值1
的地址,但也放入该内存,包含as 1
,2
,3
的ascii值的字节后跟一个值为{{的字节1}}(零)。
因此内存(在8位机器中)可能如下所示:
地址=内容(0
是字符1(一)的Ascii代码)
0x31
假设您在同一台计算机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
“指针为pt
,在这种情况下,它会在检测到已达到”字符串“的结尾时返回。
这是有原因的,不是100%的原因,它可以通过多种方式实施。
答案 5 :(得分:2)
char* pt = "123"; does two things:
1。在ROM中创建字符串文字“123”(通常在.text部分)
2.创建一个char*
,它被赋予字符串所在的内存位置的开头。
因为此操作like pt[1] = '2';
是非法的,因为您尝试写入ROM内存。
但是你可以毫无问题地将指针分配给其他内存位置。