末尾显示随机字符的数组

3

我想在C语言中测试数组,因为我刚开始学习这门语言。以下是我的代码:

#include <stdio.h>
main(){
  int i,t;
  char orig[5];
  for(i=0;i<=4;i++){
    orig[i] = '.';
  }

  printf("%s\n", orig);
}

这是我的输出结果:

.....�

这就是它的原意。那些神秘的字符是什么?我做错了什么吗?

如果我将“i<=4”更改为“i<5”,结果是相同的。但是这会打印出6个点,这同样奇怪,但已经在另一个问题中得到了回答。谢谢! - involtus
5
你没有给字符串加上结束符号。 - Christian Gibbons
5个回答

7

%sprintf()一起使用时需要一个指向字符串的指针,也就是指向以空字符结尾的字符数组的初始元素的指针。你的数组没有以空字符结尾。

因此,在寻找终止的空字符时,printf()会越界,随后引发未定义行为

如果要将其用作字符串,则必须将数组以空字符结尾。

引用:C11,第§7.21.6.1章,(重点强调)

s

如果没有l长度修饰符,则参数应该是指向字符类型数组的初始元素的指针。280)从数组中写入的字符最多到(但不包括)终止的空字符。如果指定了精度,则最多只写入那么多个字节。如果未指定精度或精度大于数组的大小,则该数组必须包含空字符。

快速解决方法:

  • 增加数组大小1,char orig[6];
  • 在循环体结束后添加一个空字符,orig[i] = '\0';

然后,打印结果。


4
char orig[5];//creates an array of 5 char.  (with indices ranging from 0 to 4)

|?|?|?|0|0|0|0|0|?|?|?|?|
      |         ^memory you do not own (your mysterious characters)
      ^start of orig

for(i=0;i<=4;i++){  //attempts to populate array with '.'
    orig[i] = '.';

|?|?|?|.|.|.|.|.|?|?|?|?|
      |         ^memory you do not own (your mysterious characters)
      ^start of orig

这将导致一个非空终止字符的数组,如果在期望C字符串的函数中使用,将会产生未定义的行为。 C字符串必须包含足够的空间来允许空终止符的存在。请更改您的声明以适应此要求。

char orig[6];

然后在循环末尾添加空终止符:
  ...
  for(i=0;i<=4;i++){
    orig[i] = '.';
  }
  orig[i] = 0;

导致:
|?|?|?|.|.|.|.|.|0|?|?|?|
      |           ^memory you do not own
      ^start of orig
< p > 注意: 因为空终止符会产生C字符串,使用它的函数知道如何解释其内容(即没有未定义的行为),并且您神秘的字符被阻止。


2

数组和字符数组之间有区别。在C语言中,可以将字符数组视为数组的一种特殊情况,其中每个元素都是char类型,并且该数组应以字符nullASCII值0)结尾。

printf()中的%s格式说明符需要一个指向以null字符结尾的字符数组的指针。您的数组没有以null结尾,因此printf函数会超出您分配的5个字符并打印后面的垃圾值('.')。

要解决问题,您需要静态分配大小比要存储的字符多一个的字符数组。在您的情况下,大小为6的字符数组将起作用。

#include <stdio.h>
int main(){
  int i,t;
  char orig[6]; // If you want to store 5 characters, allocate an array of size 6 to store null character at last position.

  for (i=0; i<=4; i++) {
    orig[i] = '.';
  }

  orig[5] = '\0';

  printf("%s\n", orig);
}

为什么要浪费一个额外的字符空间来存储null字符呢?原因在于,每当将任何数组传递给函数时,只有指向第一个元素的指针被传递到函数中(压入函数的堆栈中)。这使得函数无法确定数组的结尾(意味着像sizeof这样的操作符在函数内部不起作用,而且sizeof将返回您机器上指针的大小)。这就是为什么像memcpymemset这样的函数需要额外的参数来说明数组的大小(或者您想要操作的长度)。

然而,使用字符数组,函数可以通过寻找特殊字符(null字符)来确定数组的大小。


1
你的回答非常好,解释了为什么许多处理字符串的C函数需要字符串具有空终止符。+1。 - ryyker

1
你需要在字符串末尾添加一个NUL字符(\0)。
#include <stdio.h>

main()
{
  int  i,t;
  char orig[6];

  for(i=0;i<=4;i++){
    orig[i] = '.';
  }

  orig[i] = '\0';
  printf("%s\n", orig);
}

如果您不知道\0是什么,我强烈建议您查看ASCII表格(https://www.asciitable.com/)。
祝好运。

你没有足够的空间来存放空终止符。 - klutt
orig[i] = '\0'; 实际上有一个偏差。 - Sourav Ghosh
从 ASCII 表中,\0 是表示为 NUL '\0'(空字符) 的字符。 - Gangai Johann

1

printf需要以任何内存位置的起始指针为参数,本例中为数组,并打印直到遇到\0字符。这种类型的字符串称为null终止字符串。

因此,请在末尾添加\0并输入字符直到(数组大小-2),如下所示:

main(){
  int i,t;
  char orig[5];
  for(i=0;i<4;i++){ //less then size of array -1
    orig[i] = '.';
  }
  orig[i] = '\0'
  printf("%s\n", orig);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接