c - 对程序中的字符串进行排序 - C

标签 c gcc

所以我试图制作一个程序,从标准输入中获取一定数量的字符串,然后输出到文本文件中。 到目前为止我的代码是:

#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 分配了内存。

最佳答案

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

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

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

分配指针数组后,最好首先将所有元素设置为 NULL,然后为各个行分配内存。您不必这样做,但跟踪数组的哪些元素已初始化以及哪些元素尚未初始化会更容易。特别是,它可以让您对所有数组元素调用 free ,而不必担心已经达到了多少个。

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 接收指向行内容的指针,而不是指向行内容的指针。 How to qsort an array of pointers to char in C?对此进行了解释。

关于c - 对程序中的字符串进行排序 - C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47467875/

相关文章:

c++ - 'yield' 不是 'std::this_thread' 的成员

c++ - C++ Visual Studio 和 gcc 编译器中的空指针和空地址

c - 如何在结构体中使用指针?

c++ - 如何在我不想编辑的第 3 方代码中禁用来自 gcc 的未使用变量警告?

c - 我想知道,为什么执行后得到 "Attempt to execute non-instruction at 0x00400138"?

c - ID 的 Flex 模式给出 'Segmentation fault'

c - 告诉 C 内联函数但仍然可以调用调试器

sql - 如何检查数据库的架构

c - 在 C 中终止一个线程

将 C 字符串转换为二进制表示