【问题标题】:How to initialize string with only spaces and no trash at all?如何初始化只有空格而没有垃圾的字符串?
【发布时间】:2018-05-01 09:17:34
【问题描述】:

我在代码中的目标是用 80 个字符初始化字符串,并且仅当用户键入不是 '\0' ,' ' ,'\t' ,'\n' 的字符时。打印“非法命令”。

现在,如果用户输入例如 3 个字符的空格并按 enter 。输出为 (80-4)=76 次“非法命令”。它根本不需要打印,因为用户输入的所有字符都是'\0'' ''\t''\n' 之一。

在这种情况下请帮助我。

代码:

void main() {
  int i;
  char str[80]="";
  gets_s(str, sizeof(str));
  for (i = 0; i < 80; i++)
  {
    if ((str[i] != '\n' && str[i] != '\0' && str[i] != '\t' && str[i] != ' '))
    {
      printf_s("illegal character: %c\n", str[i]);
    }
  }
}

【问题讨论】:

  • 也许在printf_s 之后放置一个break 声明。
  • 那不是我的朋友。最后我会这样做,但这不是问题。问题是编译器输入了条件虽然我只输入空格并按回车。如果我输入 80 次空格,它将不会进入条件。但是如果我按1个时间空间然后输入,输出将是(80-2)次“非法命令”
  • edit您的问题,您需要提供一些输入示例和所需输出。
  • 另外,您可能需要指定您的系统(操作系统、编译器等),因为问题可能与系统有关。
  • void main() --> int main(void)。如果您将str 初始化为char str[80] = {'\0'};,您的输出是什么?

标签: c string


【解决方案1】:

我在代码中的目标是用 80 个字符初始化字符串,并且仅当用户键入不是 \0 , ,\t ,\n 的字符时。打印“非法com”

如果用户只输入'\0'' ''\t''\n',似乎不会打印任何消息。

char str[80]="";被指定初始化整个数组,但可能不是OP的问题。

然而脚注1comment可能解释了OP的意外输出


使这个具有挑战性的是用户输入可能包含空字符,而不仅仅是附加的。

使用getchar() 是一种直接的方法。

int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
  if (ch != ' ' && ch != '\t' && ch != '\0') {
    printf_s("illegal character code: %d\n", ch);
  }
}

gets_s(); 用于该任务比较棘手,因为它不返回读取的长度,并且输入可能包含嵌入的 空字符

要检测嵌入的空字符,缓冲区不会以'\n' 结尾,并且希望(尽管未指定。1)未使用的部分保持不变.因此,通过预填充'\n',代码可以区分附加的空字符和读取的字符。

int main(void) {
  int i;
  char str[80];
  memset(str, '\n', sizeof str);

  if (gets_s(str, sizeof str)) {
    int length = sizeof str;
    while (length > 0) {
      length--;
      if (str[length] == '\0') break;  // found appended null character
    }
    for (int i=0; i<length; i++) {
      if (str[i] != '\0' && str[i] != '\t' && str[i] != ' ') {
        printf("illegal character code: %d\n", str[i]);
      }
    }  
  }
}        

我更喜欢getchar() 方法。


1 附加的 null 字符 之后的缓冲区的值没有被指定为不变 - 但这是常见的情况。嗯,但如果它被改变,那将解释 OP 的问题。所以另一个避免的理由 gets_s();这里。

【讨论】:

  • 有趣。所以gets_s 可以在附加的 null 之后更改数组中的值(显然,在问题中显示的输出中)?
  • @Bob__ 可能是这种情况,并且可能是gets_s() 的“安全”功能,以惩罚使用该数据的代码。一个类似gets_s() 的函数返回读取的长度对于处理嵌入的空字符会更有用。
  • 只是为了明确说明 - gets_s 的 MS 版本用字节 0xfe 填充缓冲区的其余部分,某种“无效标记字节”。这只发生在调试模式下。
【解决方案2】:

当你说

char str[80] = "";

看起来您实际上并未初始化所有 80 个字符。您将第一个字符显式初始化为'\0',但看起来您的编译器为其他 79 个字符留下了随机值。 (稍后会详细介绍这一点。)

当你说

for (i = 0; i < 80; i++)

您要求循环遍历数组中的所有 80 个字符——但这没有意义。 gets_s 函数只填充了一些字符——与用户键入的字符一样多,加上一个尾随'\0'。如果用户输入的字符少于 79 个,str 中的许多字符仍然保持不变(并且可能仍然是随机的)。

尝试将循环更改为

for (i = 0; str[i] != '\0'; i++)

或者如果您想安全起见

for (i = 0; i < 80 && str[i] != '\0'; i++)

由于您的程序使用了未初始化的内存,它的行为在不同的系统上可能会有所不同。当我在我的电脑上运行你的程序时,显然所有 79 也是0,这意味着我没有看到额外的错误消息。 (所以起初我无法理解您在说什么。)但听起来,在您的系统上,它们实际上具有随机的非零值。如果您将错误消息更改为

,您可以看到这一点
printf("illegal character: 0x%02x\n", str[i]);

这将打印您看到的所有“非法”字符的(十六进制)表示。我的猜测是它们或多或少是随机数。

(正如 chux 在评论中指出的那样,您的编译器应该也将其他 79 个字符初始化为 0,所以听起来您的编译器可能是旧的,并且在这方面存在问题.)

您可以尝试的另外两件事是:

  1. str[] 的声明移到main() 之外。如果你这样做了,所有的初始化为 0,你的程序将表现得更符合你的预期。

  2. str的声明改为char str[80] = " ";""之间正好有79个空格。

但这些变化都不是一个特别好的主意。如果用户输入了 6 个字符,您真的只想检查他明确输入的 6 个字符,而不是您最初分配的全部 80 个字符。

【讨论】:

  • "您将第一个字符初始化为 '\0',其他 79 个字符将以随机值结束。" --> 在 C 中没有部分初始化。其他 79 个初始化就像一个全局的 char,到 0。
  • @chux 嗯,你是对的。 (我总是忘记这一点,我仍然习惯这种新奇的自动数组分配。)也许他的编译器弄错了;对于他看到的行为,我想不出任何其他解释。
  • @SteveSummit 请参阅 footnote 以解释为什么前 4 个之后的 str[] 可能已更改。
猜你喜欢
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2010-09-21
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
相关资源
最近更新 更多