在程序中对字符串进行排序 - C.

时间:2017-11-24 07:00:12

标签: c gcc

所以我试图创建一个从stdin接收一定数量字符串然后输出到文本文件的程序。 我到目前为止的代码是:

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

int cmpstr(const void * a, const void *b){
    const char* aa = (const char*) a;
    const char* bb = (const char*) b;
    return strcmp (aa, bb);
}

int main(int argc, char *argv[]){
  int i =0;
  int scount;
  char ** data = NULL;
  FILE * ofile;




if (argc != 3){
printf("%s \n", "The format to use this is: mySort <#of strings> <output filename>",argv[0]);
exit(EXIT_FAILURE);
}

scount = atoi(argv[1]);
if(!scount){
printf("%s \n", "Invalid number.");
exit(EXIT_FAILURE);
}

data = (char **) malloc(scount * sizeof(char*));
if(NULL == data){   
printf("Memory allocation failed\n");
exit(EXIT_FAILURE);
}

for(i = 0; i< scount; i++){
if(NULL == fgets(data[i], (int) sizeof(data), stdin)){
printf("Could not get line\n");
exit(EXIT_FAILURE);
}
}

qsort(data, scount, sizeof(char*), cmpstr);

ofile = fopen(argv[2], "w+");
if(ofile == NULL){
printf("Could not open output file. \n");
}   

for(i = 0; i<scount; i++){
    fputs(data[i], ofile);
}

fclose(ofile);

for(i=0; i<scount; i++){
    if(data[i]) free(data[i]);
}

if (data) free(data);

exit (EXIT_SUCCESS);

return 0;
}

然而,当我编译它时,它给了我一个分段错误。我尝试使用gdb调试器来尝试调试它,但它没有给我任何真正的东西,我几乎不懂如何使用gdb。但是我从gdb的使用中得到的结论是,由于我使用malloc分配了内存,因此没有足够的内存分配让我感到困惑。

1 个答案:

答案 0 :(得分:1)

data = (char **) malloc(scount * sizeof(char*));

这里为指针数组分配内存。您永远不会初始化该数组的内容。因此,当您通过将data[0]传递给fgets来访问fgets时,您正在访问未初始化的指针对象。如果你很幸运,那个未初始化的内存的内容构成了一个无效的地址,当malloc尝试在那里存储数据时,你的程序崩溃了。如果你运气不好,那个未初始化的内存的内容恰好是某个其他对象使用的某个内存块的地址,你会得到很难调试的内存损坏。

您需要初始化malloc分配的指针。与任何其他指针对象一样,根据您要执行的操作,您可以将它们初始化为NULL,指向现有对象的指针或调用malloc等函数的结果。在此程序中,您需要获取要读取的行的存储空间,因此您需要在每行上调用free。由于您事先不知道一条线的长度,因此最好在您阅读该线时完成。

一旦你分配了指针数组,然后为各行分配内存,首先将所有元素设置为NULL是个好主意。您不必这样做,但是更容易跟踪数组的哪些元素已初始化以及哪些元素尚未初始化。特别是,它允许您在所有数组元素上调用fgets(data[i], (int) sizeof(data), stdin) ,而不必担心已经达到的数量。

sizeof(data)

在这里传递data没有意义。变量char*是指向sizeof(data)的指针,因此malloc只是指针的大小。它不是指针指向的数组的大小:在编译时不知道该大小,它是您传递给fgets的参数。甚至这个大小在这里也不相关:大小是你可以读取的最大行数(乘以指向行内容的指针的大小),但max_line_length需要的是分配的内存大小对于这条线。

为了简单起见,假设您的最大行长度为data = (char **) malloc(scount * sizeof(char*)); if (data == NULL) ... // omitted error checking for (i = 0; i < scount; i++) data[i] = NULL; for (i = 0; i < scount; i++) { data[i] = malloc(max_line_length+2); // +2 for line break character and null byte to terminate the string if (data[i] == NULL) ... // omitted error checking if(NULL == fgets(data[i], max_line_length, stdin)) ... // omitted error checking ... }

cmpstr

在此之后,您将遇到注释中描述的另一个问题,因为<!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl --> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.3.0</version> </dependency> 接收指向行内容指针的指针,而不是指向行内容的指针。这在How to qsort an array of pointers to char in C?

中有解释