2010-10-14 158 views
1

我在CI中写过这样的程序,它每行按行读取一个文件(每行只有一个字),对字母进行排序,然后在每个字符中显示排序字和原始字线。对字符串中的字符进行排序的C程序

#include<stdio.h> 

int main() 
{ 
    char line[128]; 
    int i=0; 
    int j; 
    int length; 

    while(fgets(line,sizeof line,stdin) != NULL) 
    { 
    char word[128]; 

    for (i=0; line[i] != '\0'; i++) 
    { 
     word[i]=line[i]; 
    } 

    while (line[i] != '\0') 
     i++; 

    length=i; 

for (i=length-1; i >=0; i--) 
    { 
     for (j=0; j<i; j++) 
     { 
     if (line[j] > line[i]) 
     { 
      char temp; 
      temp = line[j]; 
      line[j] = line[i]; 
      line[i]=temp; 
     } 
     } 
    } 
    printf("%s %s",line,word); 

    } 
    return 0; 
} 

我编译并运行它使用下面的bash命令。

gcc -o sign sign.c 
./sign < sample_file | sort > output 

原始文件(sample_file)看起来是这样的:

computer 
test 
file 
stack 
overflow 

输出文件是这样的:

ackst stack 
cemoprtu computer 
efil file 
efloorvw overflow 
er 
estt test 
ter 
ter 

我有两个问题:

  1. 输出文件在开始处有一堆换行符(即。abou t 5-7实际文字开始前的空白行)
  2. 为什么在最后打印'ter'两次?

PS - 我知道这些都是非常基本的问题,但是我只是刚开始使用C/bash进行一个类的工作,而且我不确定哪里出错。

+1

你允许使用'string.h'函数吗?因为使用'strlen'和'strcpy'会更简单。目前,在复制之后,你并不是NUL-teriminating'word'。 – 2010-10-14 02:18:36

+0

我想我可以使用 – xbonez 2010-10-14 02:35:34

+0

这个作业吗?你可能想标记它。如果是这样,可惜你只限于C,它会成为其他几种语言的单行语言。 – Daenyth 2010-10-14 02:41:20

回答

2

问题1

此代码后,变量line包含一行文本,包括从字符串末尾的换行符

while(fgets(line,sizeof line,stdin) != NULL) 
{ 

这就是为什么你所得到的“额外“换行符。换行符的ASCII值小于'A'的ASCII值。这就是为什么一旦你对字符进行排序,换行符就会出现在每个字符串的开头。例如。 “computer \ n”变成“\ ncemoprtu”。

为了解决这个问题,你可以脱掉你的字符串末尾的换行符,for循环

if(i > 0 && word[i-1] == '\n') 
{ 
    word[i-1] = '\0'; 
    line[i-1] = '\0'; 
    --i; 
} 

...

printf("%s %s\n",line,word); /* notice the addition of the newline at the end */ 

这正好解决了问题2,作为后好吧,但请继续阅读,看看有什么不对。

问题2

环路

for (i=0; line[i] != '\0'; i++) { /* */ } 

字符串word不会空终止后(通过盲运气除外,因为它已准备好随机初始化的存储器)。这就是为什么你得到“ter”的原因,因为这是你在将单词“computer”复制到word时留下的数据的一部分。

问题3

循环后

for (i=0; line[i] != '\0'; i++) { /* */ } 

line[i] != '\0'值将始终是假的。这意味着,该代码不会做任何事

while (line[i] != '\0') 
    i++; 

这可能使问题更加明显,如果我更换for循环和while循环使用基本相同的代码,使用goto语句:

i=0; 
begin_for_loop: 
if(line[i] != '\0') 
{ 
    { 
    word[i]=line[i]; 
    } 
    i++; 
    goto begin_for_loop; 
} 

begin_while_loop: 
if(line[i] != '\0') 
{ 
    i++; 
    goto begin_while_loop; 
} 

(顺便说一句,大多数专业程序员会做任何事情,从笑到喊你,如果你提到使用goto :)我只是在这里用它来说明这一点)

我发现一个小贴士是绘制我的数组,变量等在一张纸上,然后追踪我的代码(ag ain,纸上)来调试它的工作原理。

+0

不行(因为它是一个数组)总是以空终止?在这种情况下,为什么line [i]!='\ 0'总是错误的? – xbonez 2010-10-14 02:45:26

+0

'fgets'将空终止它写入的任何缓冲区。正因为如此,'line [i] =='\ 0''将成立。换个角度考虑一下:for循环只在'line [i]!='\ 0''时退出。然后你立即再次做同样的检查。当然你会得到同样的答案。 – 2010-10-14 02:49:15

+0

但要回答*确切的*事情你问:“不行(因为它是一个数组)总是以空终止?”。不,数组可以有任何值。他们绝不会保证以null结尾,除非您手动执行该操作,或者您调用的函数可以保证执行该操作。 'fgets'做出了保证,但'word [i] = line [i];'没有。你必须自己终止'word'(只需在for循环后加':word [i] ='\ 0';')。 – 2010-10-14 02:51:59

相关问题