编写程序来读取排序并编写数组

时间:2015-12-06 14:40:11

标签: c arrays file pointers

我必须完成这项任务,而且我正在努力。

“编写一个名为sort_file的程序,它将文本文件作为输入,并生成一个输出文件,其中所有原始行都按字母顺序排列。

该计划应该做到以下几点:

提示用户输入和输出文件的名称。您可以使用适当的未排序数据准备输入文件。每行一个单词的简单文件就足够了。 声明并定义三个函数以执行以下任务: 将输入文件中的数据读入数组。 使用冒泡排序算法对数组进行排序。 将已排序的数据数组写入输出文件。“

我为这个程序创建了一个.txt文件进行排序,但是我被困住了,只是越来越困惑我越看它。这是我到目前为止所做的事情

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

#define SIZEA 50
#define SIZEB 20

void readFile(char a[]);
void sortFile(char*s[50],int n);
void writeFile();

int main( void ) {
    char name[20];

    printf("PLease enter filename:");
    scanf("%s", &*name);

    readFile(&*name);

    printf("\n");

    sortFile(name);

    printf("\n");

    writeFile();
}

void readFile(char a[]) {
    FILE *cfPtr = NULL;
    char list[SIZEA][SIZEB];
    int i = 0;
    int j = 0;

    cfPtr = fopen("unsorted.txt", "r");
    while (fgets(list[i], SIZEA, cfPtr)) {
        list[i][strlen(list[i]) - 1] = '\0';
        i++;
    }

    j = i;
    for (i = 0; i < j; i++) {
        printf("%s\n", list[i]);
    }
}

void sortfile(char*s[50], int n) {
    int i;
    int j;
    int compare;
    char temp[1][10];

    for (i = 0; i < n; i++)
        for (j = 0; j < n - 1; j++)
        {
            compare = strcmp(s[j], s[j+1]);

            if (compare > 0)
            {
                strcpy(temp[0], s[j+1]);
                strcpy(s[j+1], s[j]);
                strcpy(s[j], temp[0]);
            }
        }
}

void writeFile() {    
    FILE *cfPtr = fopen("unsorted.txt", "w");
    fwrite(list, sizeof(char), sizeof(list), cfPtr);
    fclose(cfPtr);    
}

但是我不确定要填充函数的参数是什么,或者热点以使程序的主体运行。我是新手,我发现这个话题很难理解。

1 个答案:

答案 0 :(得分:1)

关于这种界限:

scanf("%s", &*name);

在C中,数组名称降级为数组第一个字节的地址。 (有几个例外,但它们不属于此处)所以该行应该是:

scanf("%s", name); 

然而,这有几个问题。

格式说明符'%s'将允许用户溢出输入缓冲区。 %s格式说明符需要一个最大长度修饰符(并记住在使用%s格式说明符时将自动附加NUL字节。建议:

scanf("%*s", sizeof( name ) -1, name);

编译时(强烈建议执行编译和链接作为单独的步骤)始终启用所有警告,然后修复这些警告。 (对于gcc,至少使用:-Wall -Wextra -pedantic)

当原型化没有参数的函数时,不要使用:

void writeFile(); 

因为这告诉编译器会有参数,但它们尚未定义。而是使用:

void writeFile( void );

因为它告诉编译器没有参数。

注意:实际的函数声明可以/不应该在parens之间具有'void'

当声明变量和/或参数时使用有意义的名称。像char'a []'这样的参数名称(大多数)是没有意义的。而是使用类似的东西:

char * filename
or 
char filename[]

当#defined'ing数值时,强烈建议用parens包围数值以避免某些“文本替换”错误。所以这个:

#define SIZEA 50 

会更好地写成

#define SIZEA (50)

检查fopen()的返回值以确保操作成功:

FILE *fp = NULL: 
...
if( NULL == ( fp = fopen( filename, "r" ) ) 
{ // then error occurred
    perror( "fopen failed" ); 
    exit( EXIT_FAILURE ); 
} 

将使用'fopen failed'文本以及相关的系统错误消息

写入stderr

这一行:

list[i][strlen(list[i]) - 1] = '\0'; 

不一定会删除尾随换行符。 方案1:文件结束,文件中没有尾随换行符。场景2:在DOS / Windows上,换行符是2个字符,而不是1个字符。

正确的方法(还有其他几种方法)将是:

char *newline == NULL; 
if( NULL != (newline = strstr( list[i], "\n" ) ) ) 
{ 
    *newline = '\0'; 
}

关于这一行:

while (fgets(list[i], SIZEA, cfPtr))

1. if the input file contains more than SIZEA entries, 
   then the array list[] will be overrun, 
   resulting in undefined behaviour and can lead to a seg fault event. 
2. the size of each entry in the array is SIZEB. 
   Therefore suggest using: 

while ( i<SIZEA && fgets(list[i], SIZEB, cfPtr))

更健壮的方法是:char **list = NULL;然后使用realloc()更新列表中的条目数,并使用readline()getline()输入/分配内存对于列表中的每个条目。

确保将每个结果指针传递给free()以避免任何内存泄漏,

关于sortfile()函数:

这一行存在一些问题:

char temp[1][10]; 

1. an entry can be up to 20 characters line (SIZEB) 
   so 10 is inflexible and too short. 
2. does not need to be a 2D array. Suggest: 

char temp[SIZEB];
...
strcpy(temp, s[j+1]);
strcpy(s[j+1], s[j]);
strcpy(s[j], temp);

函数:writefile():

未能通过提示用户输入名称来实现输出文件名的问题场景。而是使用一些硬编码名称:unsorted.txt。该文件名具有误导性,因为输出是排序的,而不是未排序的。

关于writefile()中的这一行:

fwrite(list, sizeof(char), sizeof(list), cfPtr); 
  1. 一般来说,最佳做法是第三个参数为1,以便于执行错误检查。
  2. 表达式:sizeof(char)在标准中定义为1。 建议交换第二个和第三个参数。
  3. 但是,<newline>中没有list[]个字符,list[]数组中的大多数行都有大量未初始化的字符。所以输出将是垃圾。建议:分别输出每一行:

    char outBuf[SIZEB+3]; // +3 allows for newline and NUL byte
    for( int i = 0; i < SIZEA; i++)
    {
        int bytecount = sprintf( outBuf, "%s\n", list[i] );
        fwrite( outBuf, bytecount, 1, cfPtr );
    }
    

    注意:在SIZEA循环中使用for()假设list []数组使用所有条目,I.E。输入文件恰好包含50行。这可能不是真的,因此代码应该保留readfile()函数中读取的行数,并在sortfile()writefile()函数中使用该数字。

    关于SIZEASIZEB

    这些名字毫无意义。建议:

    #define MAX_ROWS    (50)
    #define MAX_COLUMNS (20)