一维数组是作为字符串列表还是单个字符串工作?

时间:2017-08-29 14:22:51

标签: c

#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;
}

在上面的代码中,我想知道字符串是如何保存在内存中的,因为我已经将它初始化为一维字符数组,但是数组是作为字符串列表还是单个字符串工作?为什么呢?

5 个答案:

答案 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