【问题标题】:Why does strlen() not represent the actual length of my string?为什么 strlen() 不代表我的字符串的实际长度?
【发布时间】:2018-11-29 22:45:39
【问题描述】:

基本上我有一个由多个单词组成的字符串,如下所示:"Hello world test"
如果我尝试用这样的结构打印它

printf("%s", string);

或者像这样

for (int i = 0; i < strlen(string); ++i) {
    printf("%c", string[i];
}

我总是得到这个作为输出:Hello world,我得到的 strlen 也是 11 而不是 16。

如果我尝试使用以前计算字符串中单个字符的 int 计数器打印出完全相同的字符串

for (int i = 0; i < counter; ++i) {
    printf("%c", string[i];
}

我实际上得到了正确的输出Hello world test,这导致人们相信字符串中的元素已正确分配,但由于某种原因 %s 和 strlen 只是忽略了最后一个空格之后的元素。

为什么会这样?到底是怎么回事?我该如何解决这个问题?

编辑:

请求的实际代码:

#include <stdio.h>
#include <string.h>
typedef int BOOL;
#define TRUE 1
#define FALSE 0


int main() {
    char sentence[64] = " ", reversal[64] = " ", reversal_copy[64] = " ";
    int index = 0, counter = 0;
    BOOL reset = TRUE, last_cycle = FALSE;

    printf("Enter a sentence: ");
    for (int i = 0; sentence[strlen(sentence) - 1] != '\n'; i++) {
        scanf("%c", &sentence[i]);
    }

    /* Copies the input in a string reversing it */
    for (int h = strlen(sentence) - 2, k = 0; h >= 0; h--, k++) {
        reversal[k] = sentence[h];
    }

    /* Detects the first character of a word and the last character of the same word before a space,
    switching the first char with the last, the second with the pre-last and so on*/
    for (int i = 0; i < strlen(reversal); i++) {
        if (reset == TRUE) {
            index = i;
            reset = FALSE;
        }
        if (i == strlen(reversal) - 1) {
            last_cycle = TRUE;
            counter++;
        }
        if (reversal[i] != ' ') {
            counter++;
            if (last_cycle == TRUE) {
                goto reversing;
            }
        }
        else {
        reversing:
            for (int h = index, z = counter; h < counter; h++, z--) {
                reversal_copy[h] = reversal[z - 1];
                reversal_copy[z - 1] = reversal[h];
            }
            if (last_cycle == FALSE) {
                reversal_copy[i] = ' ';
            }
            reset = TRUE;
            counter++;
        }
    }
    printf("%lu ", strlen(reversal_copy));
    for (int i = 0; i < counter; i++) {
        printf("%c", reversal_copy[i]);
    }
    printf("%s\n\n", reversal_copy);

    return 0;
}

【问题讨论】:

  • "Hello world test"如何进入stringminimal reproducible example?
  • typedef int BOOL; ~> #include &lt;stdbool.h&gt; 看在上帝的份上。该程序应该做什么(我懒得从代码中弄清楚)? size_t 的正确格式说明符 strlen() 的结果是 "%zu" btw。
  • for (int i = 0; sentence[strlen(sentence) - 1] != '\n'; i++) { 很奇怪。您应该在分配后在循环内测试sentence[i]
  • 如果您不相信,那么将您的测试 printf(%c) 循环更改为 printf(%x) 循环。你会在那里看到一个 0 (而不是 20 )
  • 旁注: strlen 具有非零执行成本,因此请尽量避免在 for 循环条件子句中使用它。更好:int revlen = strlen(reverse); for (int i = 0; i &lt; revlen; i++) { 并同样在该循环中替换它。否则,如果您的长度为 N,您将对字符串中的字符进行N*N 扫描。

标签: c


【解决方案1】:

如果strlen() 返回 11,那么您在世界“世界”之后有一个 \0 字符。

strlenprintf 都通过使用 0 终止符来确定“什么是字符串”,因此它们的行为相同也就不足为奇了。

【讨论】:

    【解决方案2】:

    虽然没有Minimal, Complete, and Verifiable example 很难回答这个问题,但我将解释您观察到的行为的最可能原因。

    带有%s 格式说明符的printfstrlen 都为您提供了相关参数所指向的空终止字符串 的长度。如果他们打印/报告长度为 11,但使用硬编码值 16 遍历整个 char 数组会得到输出“hello world test”,那么 world 后面的字符显然是空字符,'\0 '。

    【讨论】:

      【解决方案3】:

      尝试使用输入“A”作为示例运行您的程序 - 看看即使是一个单词也会出现问题。

      当你颠倒最后一个单词时出现了问题。您将尾随 '\0' 放在它前面。这可能与特殊的外壳和围绕last_cycle 逻辑的goto 有关,这很难理解。

      我认为这可能与您在该代码路径中有两个 counter++s 的事实有关。

      考虑使用一些函数让代码更简洁:

      len = strlen(reversal);
      for (start=0; start<len; start++) {
         end = find_space_or_null(reversal, start);
         if (end > start) {
          reverse_chars(reversal, start, end-1);
          start = end;
         }
      }
      

      【讨论】:

        【解决方案4】:

        程序获取用户输入的字符串,如“天空是蓝色的”,并打印出“蓝色是天空”

        这对strtok() 来说是一份完美的工作:

        #include <stddef.h>
        #include <stdio.h>
        #include <string.h>
        
        enum { MAX_LINE = 120 };
        
        int main()
        {
            char buffer[MAX_LINE];
            fgets(buffer, MAX_LINE, stdin);
        
            size_t length = strlen(buffer);
            if (length && buffer[length - 1] == '\n')  // get rid of the newline
                buffer[--length] = '\0';
        
            char *tokens[MAX_LINE] = { 0 };  // there can't be more than 60 tokens, but hey
            if ((tokens[0] = strtok(buffer, " ")) == NULL)  // no tokens? nothing to do.
                return 0;
        
            size_t i = 1;
            for (; tokens[i - 1] && i < sizeof(tokens); ++i)
                tokens[i] = strtok(NULL, " ");  // tokenize the buffer
        
            --i;  // the very last was NULL anyway.
            while (--i)  // print it reverse
                printf("%s ", tokens[i]);
            puts(buffer);
        }
        

        样本输出:

        The quick brown fox jumps over the lazy dog
        dog lazy the over jumps fox brown quick The
        

        【讨论】:

          猜你喜欢
          • 2016-05-12
          • 2011-05-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-15
          • 1970-01-01
          • 2021-05-26
          • 1970-01-01
          相关资源
          最近更新 更多