Closed. This question is off-topic. It is not currently accepting answers.
Learn more。
想改进这个问题吗?
Update the question所以堆栈溢出的值小于aa>。
两年前关闭。
将我自己从Python转换到C来学习算法课程,对于我来说,很难理解普通字符串在这个新的地狱中是如何工作的。
据我所知:
在C语言中,没有字符串本身,而是一个字符数组。
数组的变量名指向数组中第一个元素的地址(数组在内存中是对齐的),因此不需要指出每个字符。
令我困惑的是:
char greeting[] = "Hello world";
printf("%s", greeting);
1)为什么不需要像{“H”、“e”、“l”、“l”、“o”等那样向greeting[]传递数组,但是一个字符串就足够了?
2)当printf实际上是一个简单的数组时,为什么要打印出整个消息?在prinf中使用字符串格式是否经过for循环,在没有新行的情况下打印出每个元素?
char *greeting = "Hello world";
printf("%s", greeting);
3)什么?让我猜猜这个。。。C获取插入的字符串,获取其长度,创建一个字符数组,然后点(2)变魔术?指针变量的作用是什么?什么东西a[]=&a和a[0]==*a???
char *moreGreetings[] = {"Hello", "Greetings", "Good morning"};
printf("%s", moreGreetings[0]); // Returns "Hello"
4)我不能再。。。为什么调用morehalloyments[0]会调用整个字符数组“Hello”???
除非有一帮神探在幕后活动,否则我不知道这有什么意义。有人能解释一下发生了什么事吗?
电脑是外星人。他们的想法和我们完全不同。计算机不知道什么是字符串。
编程语言是一种人工翻译。Python就像阅读一本习语翻译的书。C就像读直译,即使这样也做了很多工作。
1)为什么不需要像{“H”、“e”、“l”、“l”、“o”等那样向greeting[]传递数组,但是一个字符串就足够了?
编译器帮你处理。同时,在末尾缺少空字节。那些不是角色。
C是终极的DIY语言。它来自Python,可能会让人很迷惑。C给了你最低限度的要求(是的,我看到你的汇编程序员在背后挥舞手臂,不要把事情复杂化)。它这样做A)非常快,B)让你建立任何东西。不幸的是,它并不总是以最明显的方式做到这一点。如果你不了解C语言的引擎盖下发生了什么,计算机内存如何工作的细节,你就有麻烦了。
例如,小心"
vs'
。'H'
是单个字符H,实际上是短(即1字节)整数72(确切数字取决于您的语言环境)。"H"
是一个双字符数组,{'H', '\0'}
实际上是{72, 0}
。
理解C中的字符串和所有数组的关键是,它们只是一大块分成1字节块的内存。就这样。它们甚至不存储自己的长度,您必须将其存储在其他地方(如在结构中),或者用一些东西终止列表。
C字符串是一大块内存,分成以空字节(即0)结尾的1字节块。就这样。它们在概念上是等价的。
const char *string = "Hello";
char string[] = {'H', 'e', 'l', 'l', 'o', '\0'};
两者都包含相同的字节,它们的存储方式不同。
2)当printf实际上是一个简单的数组时,为什么要打印出整个消息?在prinf中使用字符串格式是否经过for循环,在没有新行的情况下打印出每个元素?
printf
有点像Python的
str
。你告诉它如何把它转换成字符,它就会把它转换成字符。
%s
表示它是一个以空字节结尾的字符数组。
%d
表示它是一个整数。
%f
表示浮点数。所有这些东西在内存中都有不同的表示,需要不同的字符转换。
printf
如何实际工作是一个实现细节,但是您自己实现它是一个很好的练习。你可以用for循环一次写出一个字节,然后在空字节处停止。
for( const char *pos = string; pos[0] != '\0'; pos++ ) {
putchar(pos[0]);
}
请注意,不是通过数组索引,而是向前移动数组的起始位置。
string
只是指向数组开头的指针。通过将其复制到
pos
中,我可以在不影响
string
的情况下更改指针。这避免了为索引分配额外的整数,也避免了进行数组查找的额外计算。
pos[0]
只在
pos
之后读取1个字节。
是的,如果你忘记了那个空字节,它将继续读取字符串末尾的内存,直到它碰巧看到一个0,或者操作系统因为它超出了进程的界限而攻击它。
3)什么?让我猜猜这个。。。C获取插入的字符串,获取其长度,创建一个字符数组,然后点(2)变魔术?指针变量的作用是什么?什么东西a[]=&a和a[0]==*a???
不,C字符串不存储长度。为了得到长度,他们必须遍历整个字符串,然后再次遍历整个字符串来打印它。而是打印到空字节。
4)我不能再。。。为什么调用morehalloyments[0]会调用整个字符数组“Hello”???
因为
moreGreetings
是指向更多字符数组的指针数组。
char *moreGreetings[]
大致相当于
char **moreGreetings
。它是一个指向字符的指针。
这是一个字符串数组,你要求第一个字符串,所以你得到一个字符串。
请记住,Python是用C编写的(是的,现在还有其他实现)。C是堆栈的底部(几乎)。Python和其他所有程序最终都必须处理这些与C相同的“恶作剧”,但实际上它处理的是计算机如何工作的现实。
通常他们不使用C字符串,因为它们是如此笨拙和容易出错,它们自己组成,但它们仍然用数字填充固定大小的内存块,并称它们为“字符串”。
我能给你的最好建议是打开编译器警告。所有人!C编译器警告可以照亮许多简单的错误,但它们在默认情况下是关闭的。打开它们的典型方式是使用
-Wall
,但这并不是所有警告。有很多额外的东西。这是我在Makefile中使用的公式(有Makefile)。
CFLAGS += -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic $(OPTIMIZE)
这将打开“所有”警告、“额外”警告以及一些我发现有用的额外特定警告。它说我使用的是1999年的I so C标准(稍后会详细介绍),我希望编译器在遵循该标准方面比较迂腐,这样我的代码就可以在编译器和环境之间移植。我做了很多开源的工作,但是当你开始的时候会很好,这样你就不会沉迷于非标准编译器扩展。
关于标准。C很老了,1990年才被标准化。很多很多人都学会了用非标准C编写代码,你可以在很多C教材中看到这一点。尽管有2011年的标准,但许多C程序员编写并教授C90甚至更早的版本。甚至C99也被许多人认为是“新的”。Visual Studio在标准遵从性方面尤其糟糕,但它们终于赶上了最新版本。