#include <stdio.h>
#include <string.h>
int main()
{
int i;
char a[10];
for(i=0;i<10;i++)
{
scanf("%s",a);// >how this line is working in memory.
}
return 0;
}
在上面的代码中,我想知道字符串是如何保存在内存中的,因为我已经将它初始化为一维字符数组,但是数组是作为字符串列表还是单个字符串工作?为什么呢?
答案 0 :(得分:5)
在C中,字符串是由0值字符终止的字符值序列 - IOW,字符串"Hello"
表示为字符序列'H'
, 'e'
,'l'
,'l'
,'o'
,0
。字符串存储在char
(或{{1>} 宽字符串)的数组中:
wchar_t
在内存中,char str[] = "Hello";
看起来像这样:
str
可以在一个1D阵列中存储多个字符串,尽管几乎没有人这样做:
+---+
str: |'H'| str[0]
+---+
|'e'| str[1]
+---+
|'l'| str[2]
+---+
|'l'| str[3]
+---+
|'o'| str[4]
+---+
| 0 | str[5]
+---+
在记忆中:
char strs[] = "foo\0bar";
字符串 +---+
strs: |'f'| strs[0]
+---+
|'o'| strs[1]
+---+
|'o'| strs[2]
+---+
| 0 | strs[3]
+---+
|'b'| strs[4]
+---+
|'a'| strs[5]
+---+
|'r'| strs[6]
+---+
| 0 | strs[7]
+---+
从"foo"
开始存储,而字符串strs[0]
从"bar"
开始存储。
通常,要存储字符串的数组,您要么使用strs[4]
的2D数组:
char
或指向char strs[][MAX_STR_LEN] = { "foo", "bar", "bletch" };
的一维指针数组:
char
在第一种情况下,字符串的内容存储在char *strs[] = { "foo", "bar", "bletch" };
数组中:
strs
在第二个中,每个 +---+---+---+---+---+---+---+
strs: |'f'|'o'|'o'| 0 | ? | ? | ? |
+---+---+---+---+---+---+---+
|'b'|'a'|'r'| 0 | ? | ? | ? |
+---+---+---+---+---+---+---+
|'b'|'l'|'e'|'t'|'c'|'h'| 0 |
+---+---+---+---+---+---+---+
指向到strs[i]
的不同的一维数组:
char
在您的代码中, +---+ +---+---+---+---+
strs: | | strs[0] ------> |'f'|'o'|'o'| 0 |
+---+ +---+---+---+---+
| | strs[1] ----+
+---+ | +---+---+---+---+
| | strs[2] -+ +-> |'b'|'a'|'r'| 0 |
+---+ | +---+---+---+---+
|
| +---+---+---+---+---+---+---+
+----> |'b'|'l'|'e'|'t'|'c'|'h'| 0 |
+---+---+---+---+---+---+---+
可以(并且通常用于)存储长度为9个字符的单个字符串(不包括0终止符)。就像我说的,几乎没有人在一个1D数组中存储多个字符串,但它是可能的(在这种情况下,a
可以存储2个4字符字符串)。
答案 1 :(得分:2)
char a[10];
您已为a
分配了10个字节的堆栈。但是现在,它包含垃圾,因为你从来没有给它一个价值。
Scanf
并不知道这些。它所做的就是将标准输入中的字节复制到a
,而不知道它的大小。
你为什么要做10次循环?您将覆盖a
每个循环迭代,因此您只能获得最终时间的值。
答案 2 :(得分:2)
字符串是每个定义一个以空字符结尾的字符数组。因此,每个字符数组在某处包含\0
时都会成为字符串,从而定义该字符串的结尾。
在内存中,字符串只是依次放置一堆字节(为简单而非必要)。以字符串"Hello"
为例
+---+---+---+---+---+---+
| H | e | l | l | o | \0|
+---+---+---+---+---+---+
您的数组char a[10]
指向此类内存位置的开头(示例中为&#39; H&#39;),并且有足够的空间存储10个字符。
通过使用scanf
,您将在该缓冲区中存储一个字符串(字符序列+终止\0
)(一遍又一遍)。 scanf
将字符存储在那里,并在写入最后一个元素后向元素添加终止\0
。这允许您安全地存储长度最多为9个字符的任何字符序列,因为第10个字符必须是\0
答案 3 :(得分:1)
你在循环中写入相同的缓冲区10次,这意味着缓冲区将包含在上次读取时输入的数据,之前的9个字符串将丢失。
同样输入超过9个字符会导致缓冲区溢出,从而调用undefined behavior。
您应该限制从输入缓冲区扫描的字符数,然后clear the rest of the buffer。 (不是fflush(stdin);
)
scanf("%9s",a);
一维数组是作为字符串列表还是单个字符串工作?
如果它以null字符终止,那么是,它的字符串,就像这样。 a
是第一个元素的地址。
+---+---+---+---+---+---+----+
| S | t | r | i | n | g | \0 |
+---+---+---+---+---+---+----+
a a+1 a+2
如果你传递这个数组即。到printf()
,他会打印所有字符,直到他到达\0
。
如果您想阅读字符串列表,则必须声明 2D数组或指向指针指向字符,并为指针分配足够的内存。
int c;
char a[10][10];
for(i=0;i<10;i++)
{
scanf("%9s",a[i]);
while ((c = getchar()) != '\n' && c != EOF) ;
}
答案 4 :(得分:1)
一维数组是作为字符串列表还是单个字符串工作?
相当广泛的问题。
char a[10];
声明了表格a,其大小为10 char
元素
char *a[10];
声明了表a,其大小为10 char *
个元素,可以指向字符串(当你为它分配内存并复制有效的C字符串时)
在你的代码中:
'的scanf( “%S”,一个);' a
表示数组的第一个元素的地址。因此,每次覆盖以前的内容时,scanf都会在那里写入数据。如果您的扫描输入需要存储更多10个元素(包括尾随0
),您将获得一个UB且非常可能的SEGFAUT