2015-12-28 16 views
0

我想从文件中读取字符作为整数,并将它们转换为数组中的字符串后,在mergesort算法中比较字符串。我能够打印出字符串,但是当char[]数组传递给mergesort算法时,程序在strcmp()步骤中崩溃,该步骤位于合并排序的merge()步骤中。C - 如何将字符数组传递给函数进行排序?

我测试,看我的临时char[]数组不正确初始化,所以我觉得这个问题是我没有通过原始char[]阵列“夏尔”到mergsort功能。

我失去了如何做到这一点。我借用了web上的mergesort算法,它适用于int阵列,但将int[]阵列更改为char[]阵列的简单更改不起作用。

如何获得char[]阵列,我希望排序完成并在mergesort函数中进行初始化?

的排列是这样的文本文件:

AAAAB

aaaba

aabaa

abaaa

baaaa

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

int main(void) { 

int arr[243][6]; 

//This is the array that I want to store my strings 
char *charr[243][6]; 

int c, i = 0 , j = 0; 
FILE *file; 
file = fopen("permutations.txt", "r"); 
if (file) { 
    while ((c = getc(file)) != EOF) { 
     // we are reading each char in the string 
     //every time we hit a new line char (\n = 10) 
     //advance the array one, otherwise add the 
     // char 
     if (c != 10) { 
      arr[i][j] = c; 
      j++; 
     } 
     else { 
      arr[i][j] = c; 
      sprintf(charr[i], "%d%d%d%d%d%d", arr[i][0], arr[i][1], 
       arr[i][2], arr[i][3], arr[i][4]); 
      i++; 
      j = 0; 
     } 
    } 
    fclose(file); 
} 

if (strcmp(charr[0],charr[1]) < 0) 
    printf("less\n"); 
else 
    printf("other\n"); 

r_mergesort(charr,0,242); 

for (int k = 0; k < 243; k++) { 
    printf(charr[k]); 
    for (int l = 0; l < 6; l++) { 
     putchar(arr[k][l]); 
    } 
} 
return 0; 
} 

/*l is for left index and r is right index of the sub-array*/ 
void r_mergesort (char arr[], int l, int r) { 
    //base case 
    if (l < r) { 
     //divide 
     int m = (l + r) /2; 
     // recursively sort halves 
     r_mergesort(arr, l, m); 
     r_mergesort(arr, m + 1, r); 
     // merge results 
     merge(arr, l, m, r); 
    } 
} 

void merge (char arr[], int l, int m, int r) { 
    int i, j, k; 
    int n1 = m - l + 1; 
    int n2 = r - m; 
    // create temp arrays 
    char left[n1], right[n2]; 
    // copy data to temp arrays 
    for (i = 0; i < n1; i++) { 
     left[i] = arr[l + i]; 
    } 
    for (j = 0; j < n2; j++) 
     right[j] = arr[m + 1 + j]; 
    // merge the temp arrays back into arr[] 
    i = 0; 
    j = 0; 
    k = l; 
    while (i < n1 && j < n2) { 
     if (strcmp(left[i], right[j]) < 0) { 
      arr[k] = left[i]; 
      i++; 
     } 
     else { 
      arr[k] = right[j]; 
      j++; 
     } 
     k++; 
    } 
    //copy the remaining elements of left[] 
    while (i < n1) { 
     arr[k] = left[i]; 
     i++; 
     k++; 
    } 
    //copy the remaining elements of right[] 
    while (i < n2) { 
     arr[k] = right[j]; 
     j++; 
     k++; 
    } 
} 
+0

阵列衰减到指针,所以通过在阵列的大小。 – erip

+2

尝试'char * charr [243] [6];' - >'char charr [243] [7];' – BLUEPIXY

+0

这是一个更大的问题。但是,这将限制字符串长度为5(全部243个......)。 –

回答

0

虽然以字符为导向的输入(例如,如果像你所描述的那样,你的permutations.txt包含一个可能的每行排列,那么使用面向行的输入将会简化你的阅读(我怀疑你的问题的大部分在哪里)。所以,让我们开始正确地阅读您的数据文件,以解决您的问题。

使用面向行的输入,您的主要功能是fgetsgetline。每个人都有一定的优缺点。由于您仅处理静态声明,因此我们将使用下面的fgets作为示例。

有一点要注意的与面向行的输入,是fgets将读取直到newline'\n')是遭遇或指定的字符的最大数目(减1个留有余地NUL - 终止子)。这意味着你的情况是,如果你已经声明charr[243][7]并且每行有6个字符(加上'\n'对于总共7个字符),如果你没有增加字符串的大小来增加字符的话,你会遇到问题将'\n'作为每行的一部分来阅读(并且还提供了空终端的空间)。

基本上会发生什么是你会告诉fgets阅读的7字符一个最大值,这意味着它会读取你的排列字符的所有6,但离开'\n'在该行未读的结束。您在fgets的下一个电话将只能读取'\n'。要解决整个问题,只需声明charr[243][8] = {{0}};即可完整读取每一行。

你可能会说'这听起来不太简单' - 我只是想确保并给出一个彻底的解释,所以你最终不会陷入一个微妙的阅读1那整条线。当然,由于所有面向行的输入函数都读取并包含'\n'作为其读取的一部分,因此您需要从存储在数组中的stings中删除换行符。的说明后,希望该示例将使读更加清晰:

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

#define MAXR 243 
#define MAXC 8 

int main (int argc, char **argv) { 

    char charr[MAXR][MAXC] = {{0}}; 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 
    size_t i = 0; 

    if (!fp) { 
     fprintf (stderr, "error: file open failed '%s'\n", argv[1]); 
     return 1; 
    } 

    while (i < MAXR && fgets (charr[i], MAXC, fp)) 
    { 
     /* get length, strip trailing newline */ 
     size_t len = strlen (charr[i]); 
     if (charr[i][len-1] == '\n') charr[i][len-1] = 0; 

     printf (" charr[%zu] : %s\n", i, charr[i]); 

     i++; 
    } 
    if (fp != stdin) fclose (fp); 

    return 0; 
} 

上面简单地将代码读取并打印(具有线索引)每个置换从给定为第一个参数到程序文件中读出(如果没有给出文件名,则从stdin)。这只是确认您的permutations.txt文件的读取开始。

编译

gcc -Wall -Wextra -O3 -o bin/readperm readperm.c 

测试输入(permutations.txt)

$ cat permutations.txt 
123456 
234561 
345612 
456123 

输出

$ ./bin/readperm permutations.txt 
charr[0] : 123456 
charr[1] : 234561 
charr[2] : 345612 
charr[3] : 456123 

fgetsgetline面向行的输入的主要工具,而我很少推荐scanf系列函数,如果您的permutations.txt文件完全按照您所描述的fscanf在此情况下可以非常有效地使用。通常,格式字符串和适当的格式说明符的选择是新C程序员适合的。由于fscanf不需要您阅读换行符,因此可以使用char charr[243][7] = {{0}};声明,而不必担心删除包含的newline。具体来说,可以更换读取循环以上:

while (i < MAXR && fscanf (fp, " %[^\n]%*c", charr[i]) == 1) 
    { 
     printf (" charr[%zu] : %s\n", i, charr[i]); 

     i++; 
    } 

注意格式说明" %[^\n]%*c"的选择。开头"'%'之间的前导space将跳过第一个字符前的任何空格。字符案例表达式用作格式说明符%[^\n]将读取最多但不包含newline的所有字符。 分配抑制%*c将读取并丢弃'\n'而不将其包含在您的字符串中(或由fscanf返回的匹配计数)。

你可以简单地使用" %s"格式说明,并完成相同的读你的情况,但这已经消除了格式字符串那就是了解正确使用至关重要的各个部分的说明scanf功能家族。

最后,注意上面的使用返回== 1fscanf返回成功转换的次数(根据格式说明符)。因此,只要fscanf在每次被调用时都对字符串进行单次转换,您就想继续阅读。当它未能作出适当的转换你读的循环终止(你可以将返回一个变量和循环体内检查,以确认EOF与读取错误)

让当你拿到你的阅读我知道permutations.txt整理出来,我们将在确认您的阅读已修复之后继续处理您所遇到的任何问题。

0

尝试char *charr[243][6]; - > char charr[243][7];

char arr[] - > char arr[][7]你认为这是

sprintf(charr[i], "%d%d%d%d%d%d"修改后的方案 - > sprintf(charr[i], "%c%c%c%c%c%c"

–   BLUEPIXY

三个转变英语新这些让我走上了正轨的那些人是受人诟病的。我不得不初始化合并算法中每个字符串的整个长度,但仅仅说左[i] = arr [l + i]是不够的。

  – lefunction