【问题标题】:Why won't this printf() statement print two string variables in C?为什么这个 printf() 语句不会在 C 中打印两个字符串变量?
【发布时间】:2012-08-01 19:51:56
【问题描述】:

我在学习 C 时一直在疯狂地研究。我一直在调试 C 程序,我认为我遇到了一些重大问题here。现在我有关键问题。我做了一个虚拟程序,在一个语句中打印两个字符串,如下所示:

   #include<stdio.h>

int main(int argc, char* argv[])
{
    char *herp = "Derp";
    char *derp = "Herp";

    printf("Herp %s Derp %s\n", herp, derp);

    return 0;
}

这会按预期打印出来。我明白了

Herp Derp Derp Herp

所以,我想,让我通过做类似的事情来调试我自己的程序。我的程序中的以下行

printf("word is: %s and jumbled word is: %s\n", word, jumbleWord);

应该打印出类似的东西

Word is: word and jumbled word is: dowr

但它会打印出类似的东西

and jumbled word is: dowr

输出的第一部分去哪儿了?我需要能够在同一行上打印它们以进行调试。此外,像这样的声明不起作用的事实告诉我,正在发生非常奇怪的事情,我因为把头发扯掉而秃了。正如我链接的帖子所表明的那样,我最终想比较这些字符串值,但是如果 printf() 不能正常工作,我怎么能这样做呢?

我在下面发布了整个程序,以便您可以看到发生的一切。我只是在学习如何使用指针。当我想弄乱一个单词时,我最初有两个指针指向同一个内存,但效果不太好!所以我解决了这个问题,得到了两个单独的内存空间,里面有我需要的单词。现在,我只是无法打印它们。鉴于下面的代码,这一切都说得通:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_WORD_LENGTH 25

//Define global variables 
int numWords; 

//Preprocessed Functions 
void jumblegame();
void readFile(char *[]);
void jumbleWord(char *);
void guess(char *,char *); 

int main(int argc, char* argv[])
{
    jumblegame();
    return 0;
}

void jumblegame()
{
    //Load File 
        int x = 5050; //Rows
        char *words[x];
        readFile(words);

    //Define score variables 
        int totalScore = 0;
        int currentScore = 0; 

   //Repeatedly pick a random work, randomly jumble it, and let the user guess what it is
         srand((unsigned int)time(NULL));
         int randomNum = rand() % numWords + 1;

         char source[MAX_WORD_LENGTH + 1];
         char jumble[MAX_WORD_LENGTH + 1];

         strncpy(source, words[randomNum], MAX_WORD_LENGTH + 1);
         strncpy(jumble, words[randomNum],MAX_WORD_LENGTH + 1);

         jumbleWord(jumble);

         guess(source, jumble);
         //printf("Random word is: %s\n ", words[randomNum]);
         //randomly jumble it           
}

void readFile(char *array[5049]) 
{
    char line[256]; //This is to to grab each string in the file and put it in a line. 
    int z = 0; //Indice for the array

    FILE *file;
    file = fopen("words.txt","r");

    //Check to make sure file can open 
    if(file == NULL)
    {
        printf("Error: File does not open.");
        exit(1);
    }
    //Otherwise, read file into array  
    else
    {
        while(!feof(file))//The file will loop until end of file
        {
           if((fgets(line,256,file))!= NULL)//If the line isn't empty
           {
             int len = strlen(line); 
             if (len > 0 && line[len - 1] == '\n') line[len - 1] = '\0';
             array[z] = malloc(strlen(line) + 1);
             strcpy(array[z],line);
             z++;
           }    
        }
    }
    fclose(file);
    numWords = z; 
}

void jumbleWord(char *word)
{
    int wordSize = strlen(word) - 1; 
    //durstenfeld Implementation of Fischer-Yates Shuffle
        int i; 
        int j; 
        char temp;
        for(i = wordSize - 1; i > 0; i--)
        {
            j =  rand() % (i + 1);
            temp = word[j];
            word[j] = word[i];
            word[i] = temp;
        }
}

void guess(char *word, char *jumbleWord)
{
     printf("original word is: %s\n", word);
     printf("jumbled word is: %s\n", jumbleWord);
     printf("source is: %s and jumbled word is: %s\n", word, jumbleWord);
}

我认为此时大多数人都会烧掉 C 并为自己做得不好而扇耳光。但是,我将继续运输。所以让我为任何愚蠢的行为道歉,但请知道我已经花了很多时间可能真的很愚蠢并盯着这个。我很想说,“嘿,C 太愚蠢了,因为它不会按照我说的去做”。不幸的是,我无法相信这一点。我认为它正在做我告诉它做的事情,但我离这个问题太近了,看不出我做错了什么。

一如既往,感谢您的帮助。致以最深的敬意, 极客欧米茄

【问题讨论】:

  • 您不应在每个rand 之前调用srand,而应在程序开始时调用一次。
  • 旁注:char *jumbledWord= jumbleWord(jumble);,您 jumbleWord 更改了作为其参数本身给出的字符串。所以jumbleWordjumble 在这次调用之后将是完全相同的东西。
  • 谢谢克里斯。我修好了。 Shahbaz,将解决这个问题。我想到了一种方法,这可能是多余的。正如我所说,指针的新手。 :-) 尽管如此,还是遇到了那个奇怪的问题。 :-(
  • 数组在 C 中基于 0,因此当使用 randomNum 作为 words[] 的索引时,int randomNum = rand() % 5049 + 1; 行会产生一个错误。
  • 非常感谢大家回答我的问题,然后超越职责范围,真正帮助指出糟糕的编码实践。你是周围最好的一群人。我真的在这些东西上扯了我的头发,从你们那里学到了很多东西。 + 代表你们所有人,如果我亲自认识您,如果您愿意,我会请您喝一杯啤酒。

标签: c string debugging printf


【解决方案1】:

您在单词末尾有一个回车 '\r'

回车将写入光标移动到屏幕左侧,所以它正在写入它,但它正在覆盖已经存在的内容。

【讨论】:

  • 显然他在 Windows 机器上创建了文件。
  • 我添加了解释为什么这很重要。希望你不要介意。
  • 我应该使用 if 语句来摆脱它吗?像下面的代码: int len = strlen(line); if(len > 0 && line[len - 1] == '\r') line[len - 1] = ''; ?这能解决这个问题吗?
  • if (len &gt; 0 &amp;&amp; (line[len-1] == '\n' || line[len-1] == '\r')) { line[len-1] = '\0'; if (len &gt; 1 &amp;&amp; line[len-2] == '\r') line[len-2] = '\0'; }
  • 您也可以使用strchr查找第一个'\r',如果找到则替换为'\0';使用 gnu libc 的 strchrnul 会更容易一些
【解决方案2】:

您的文字文件实际上有5049 条目吗?即使它没有,你也不应该假设它有。您的readFile 函数应该在读取文件后确定您的words 数组中实际 存在多少个单词,否则,对words 数组进行随机索引将导致访问未初始化的字符串,我怀疑这会导致您的内存损坏。

因此,如果 readFile 只看到 10 个单词,您应该只在索引 0..9 之间选择一个随机单词。您已经在 readFile 方法中保留了变量 z 中的字数,与您的其余代码共享。

当您为数组选择随机索引时,请注意,由于数组是从 0 开始的,因此您应该通过有效数组元素的数量来获取随机数和 mod。所以使用int randomNum = rand() % 5049; 而不使用+1

此外,所有这些strlen/+1/-1 的东西都是不必要且令人困惑的,对于字符串,更喜欢strncpy 而不是memcpy(和strcpy),你不需要处理它。请注意strlen 的结果 包含空终止符,因此您无需使用-1 来说明这一点。我认为您的 jumbleWord 函数应该始终忽略混乱中的最后一个 char

对字符串分配使用此策略:您有MAX_WORD_LENGTH,在游戏中将字符串声明为char word[MAX_WORD_LENGTH + 1]char *word = malloc(MAX_WORD_LENGTH + 1)。现在要复制字符串,请使用strncpy(src, dest, MAX_WORD_LENGTH)

【讨论】:

  • 在这种情况下,请参阅关于与 rand 一对一的说明。但是你仍然应该坚持实际阅读的字数,这并不难,并且可以防止短文件的潜在错误
  • 当我只用 2 更改运行您的代码时:在readFile 中设置全局numWords == z,并使用int randomNum = rand() % numWords; 选择一个rand,代码运行良好,除了最后一个char 永远不会混乱,请参阅我的回答。不过,这里可能还有其他问题,很难说。但这应该会让你继续前进。
  • 请注意,strncpy() 也可能很危险。 strncpy(dst, src, strlen(src))永远 null 终止dst。为了确定你应该在另一个步骤中执行 strncpy(dst, src, strlen(src) + 1) 或特别是 null 终止 dst
  • @DaveRager natch,但我认为这超出了问题的范围:他最终会解决这个问题。我在系统里有回复:这个问题:stackoverflow.com/questions/10943033/…
  • @pb2q 对,我只是认为指出这一点可能很重要。在您的回答中,您谈到 strlen +1/-1 是不必要的,然后指向 strncpy 所以他不需要处理它。 IMO strncpy 是绝对需要strlen + 1 的地方。
猜你喜欢
  • 2017-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-08
  • 2014-08-23
  • 1970-01-01
相关资源
最近更新 更多