簡體   English   中英

在C中對結構數組進行排序

[英]Sorting an array of structs in C

我們在課堂上被分配了一個任務,以對結構數組進行排序。 分配完任務后,我們討論了使用數組指針對列表進行排序的方法,因為它比大多數人的方法更有效。

我決定也嘗試這樣做,但是我遇到了一些我無法解決的問題。

http://pastebin.com/Cs3y39yu

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>

typedef struct stage2{//standard dec of the struct field
     char need;
         double ring;
         char fight[8];
         int32_t uncle;
         char game;
         double war;
         int8_t train;
         uint32_t beds;
         float crook;
         int32_t feast;
         int32_t rabbits;
         int32_t chin;
         int8_t ground;
         char veil;
         uint32_t flowers;
         int8_t adjustment;
         int16_t pets;
} stage2;

void usage(){//usage method to handle areas
        fprintf(stderr,"File not found\n");//prints to stderr
        exit(1);//exits the program
}

int needS(const void *v1, const void *v2)
{
    const stage2 *p1 = v1;
    const stage2 *p2 = v2;
        printf("%c %c \n",p1->need,p2->need);
    return 0;
}


int main(int argc, char** argv){
        if(argc != 3){//checks for a input files, only 1
          usage();//if not runs usage
  }
  int structSize = 60;//size of structs in bytes, sizeof() doesnt return correct val
  char* fileName = argv[1];  //pull input filename
  FILE *file = fopen(fileName, "r");//opens in read mode
  fseek(file, 0, SEEK_END);  //goes to end of file
  long fileSize = ftell(file);  //saves filesize
  char *vals = malloc(fileSize);  //allocates the correct size for array based on its filesize
  fseek(file, 0, SEEK_SET);  //returns to start of file
  fread(vals, 1, fileSize, file);  //reads the file into char array vals
  fclose(file); //closes file
  int structAmount = fileSize/structSize; //determines amount of structs we need
  stage2 mainArray[structAmount]; //makes array of structs correct size


  int j;//loop variables
  int i;


  printf("need, ring, fight, uncle, game, war, train, beds, crook, feast, rabbits, chin, ground, veil, flowers, adjustment, pets\n");//prints our struct names

  for(i = 0; i < structAmount; i ++){//initialises the array vals
        mainArray[i].need = *(&vals[0+(i*60)]);
        mainArray[i].ring = *((double *)&vals[1+(i*60)]);
        for(j = 0;j<9;j++){
          mainArray[i].fight[j] = *(&vals[j+9+(i*60)]);
        }
        mainArray[i].uncle = *((int32_t *)&vals[17+(i*60)]);
        mainArray[i].game = *(&vals[21+(i*60)]);
        mainArray[i].war = *((double *)&vals[22+(i*60)]);
        mainArray[i].train = *((int8_t *)&vals[30+(i*60)]);
        mainArray[i].beds = *((uint32_t *)&vals[31+(i*60)]);   
        mainArray[i].crook = *((float *)&vals[35+(i*60)]);
        mainArray[i].feast = *((int32_t *)&vals[39+(i*60)]);
        mainArray[i].rabbits = *((int32_t *)&vals[43+(i*60)]);
        mainArray[i].chin = *((int32_t *)&vals[47+(i*60)]);
        mainArray[i].ground = *((int8_t *)&vals[51+(i*60)]);
        mainArray[i].veil = *(&vals[52+(i*60)]);
        mainArray[i].flowers = *((uint32_t *)&vals[53+(i*60)]);
        mainArray[i].adjustment = *((int8_t *)&vals[57+(i*60)]);
        mainArray[i].pets = *((int16_t *)&vals[58+(i*60)]);    
  }

  for(i = 0; i < structAmount; i ++){//prints
        printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
        mainArray[i].need,mainArray[i].ring,mainArray[i].fight,mainArray[i].uncle,mainArray[i].game,mainArray[i].war,mainArray[i].train,
        mainArray[i].beds,mainArray[i].crook,mainArray[i].feast,mainArray[i].rabbits,mainArray[i].chin,mainArray[i].ground,mainArray[i].veil,
        mainArray[i].flowers,mainArray[i].adjustment,mainArray[i].pets);//prints

  }
  free(vals);//frees the memory we allocated to vals

  stage2 *array = malloc(structAmount * structSize);

  for(i = 0; i < structAmount; i ++){
        array[i] = mainArray[i];  
  }
  printf("Before Sort\n\n");  
  for(i = 0; i < structAmount; i ++){
          printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
  array[i].need,array[i].ring,array[i].fight,array[i].uncle,array[i].game,array[i].war,array[i].train,
  array[i].beds,array[i].crook,array[i].feast,array[i].rabbits,array[i].chin,array[i].ground,array[i].veil,
  array[i].flowers,array[i].adjustment,array[i].pets);//prints 
  }
  qsort(array, structAmount,structSize,needS);


  printf("After Sort\n\n");  
  for(i = 0; i < structAmount; i ++){
          printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
  array[i].need,array[i].ring,array[i].fight,array[i].uncle,array[i].game,array[i].war,array[i].train,
  array[i].beds,array[i].crook,array[i].feast,array[i].rabbits,array[i].chin,array[i].ground,array[i].veil,
  array[i].flowers,array[i].adjustment,array[i].pets);//prints 
  }

  FILE *my_file = fopen(argv[2], "wb");
  for(i = 0; i < structAmount; i ++){
          fwrite(&mainArray[i].need, sizeof(char), 1, my_file);
          fwrite(&mainArray[i].ring, sizeof(double), 1, my_file);
          fwrite(&mainArray[i].fight, sizeof(char[8]), 1, my_file);
          fwrite(&mainArray[i].uncle, sizeof(int32_t), 1, my_file);
          fwrite(&mainArray[i].game, sizeof(char), 1, my_file);
          fwrite(&mainArray[i].war, sizeof(double), 1, my_file);
          fwrite(&mainArray[i].train, sizeof(int8_t), 1, my_file);
          fwrite(&mainArray[i].beds, sizeof(uint32_t), 1, my_file);
          fwrite(&mainArray[i].crook, sizeof(float), 1, my_file);
          fwrite(&mainArray[i].feast, sizeof(int32_t), 1, my_file);
          fwrite(&mainArray[i].rabbits, sizeof(int32_t), 1, my_file);
          fwrite(&mainArray[i].chin, sizeof(int32_t), 1, my_file);
          fwrite(&mainArray[i].ground, sizeof(int8_t), 1, my_file);
          fwrite(&mainArray[i].veil, sizeof(char), 1, my_file);
          fwrite(&mainArray[i].flowers, sizeof(uint32_t), 1, my_file);
          fwrite(&mainArray[i].adjustment, sizeof(int8_t), 1, my_file);
          fwrite(&mainArray[i].pets, sizeof(int16_t), 1, my_file);
  }

  fclose(my_file);

  return 0;//return statement
}

有指向我一直在努力的代碼的鏈接。 我的主要問題是,從我收集的數據來看,當使用排序比較方法needS (第31行)進行排序的第一次執行時,它應該返回數組中前兩個結構的第一個字段並打印它們(我知道這不是有效的排序方法,但要確保變量符合我的期望)。 但是,事實並非如此。 p1變量將打印出我期望的結果,但是p2變量不會。 從現在開始,每次使用此方法都會返回垃圾值(我認為)。

有什么我想念的或做錯的嗎?

您的問題在這一行:

int structSize = 60;  //size of structs in bytes, sizeof() doesn't return correct val

你錯了; sizeof()確實返回正確的大小。 無論您做什么,都是虛假的。 您需要回到序列化的基礎知識。 您將需要正確寫入數據。 您應該能夠通過一次讀取操作將所有數據讀取到陣列中。 如果輸入中的每條記錄確實有60個字節,則存在嚴重問題。

請注意,您在存儲器中的結構布局在大多數系統之間(在某些char need;之間)浪費了7個字節(某些情況下為3個字節) char need; double ring; 元素。 char game;之間也存在類似的差距char game; double war; ,以及int8_t train;之間的另一個間隔(通常為3個字節) int8_t train; uint32_t beds; ,以及char veil;之間的另一個類似間隔(通常是2個字節) char veil; uint32_t flowers; (因為char veil;前面是int8_t ground;並且int8_t adjustment;int16_t pets;之間的間隔為1 int16_t pets; —我不能保證已經發現所有間隔)。

要了解有關結構布局和填充的更多信息,請參見為什么結構的sizeof不等於每個成員的sizeof之和? 根據稻田的建議。

為了最大程度地減少浪費的空間,試探法是將具有較大基本類型的成員放在具有較小基本類型的成員之前。 因此,所有double成員都應位於任何char成員之前。 如果成員是數組類型,請忽略該數組並查看基本類型的大小。 例如char fight[8]; 最好與其他char成員放在最后,盡管考慮到它是8字節的倍數,它可以保留在原來的位置,但是保持一致更簡單。 在64位系統上,指針應被視為8字節,在32位系統上,指針應被視為4字節。 將指針放在非指針類型(例如long longdouble (通常每個8個字節)與較小的非指針類型(例如intuint32_t long類型很麻煩; 它可以是4或8字節,具體取決於(在Windows上,甚至Windows 64位為4字節;在64位Unix上為8字節,在32-but Unix上為4字節)。

needS函數需要返回一個適合於對數組中的項目進行排序的值。

int needS(const void *v1, const void *v2)
{
    const stage2 *p1 = v1;
    const stage2 *p2 = v2;
    printf("%c %c \n",p1->need,p2->need);

    // Something like:
    return (p1->need < p2->need);
}

您已經將數據文件中的“打包”結構大小與分配的內存結構數組混淆了(默認情況下, struct stage2將具有額外的填充以有效地對齊數據類型)。 這行是問題所在:

stage2 *array = malloc(structAmount * structSize);

它應該是:

stage2 *array = malloc(structAmount * sizeof(stage2));

您對qsort調用也需要相應地進行更新:

qsort(array, structAmount, sizeof(stage2), needS);

除了其他張貼者關於比較功能和結構大小的好答案外,您也不會按指針排序,這是您的初衷。

在代碼中,對大型結構的整個數組的副本進行排序。 當按指針排序時,您將創建一個指向原始數組元素的輔助指針數組,然后通過它們所指向的數據對這些指針進行排序。 這將保留原始數組的完整性。

然后,您的比較函數必須將void *指針視為指向您的結構的指針。 下面的示例(具有高度刪節的結構)。

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

typedef struct stage2 {
    int need;
} stage2;

int needS(const void *v1, const void *v2)
{
    stage2 *const *p1 = v1;
    stage2 *const *p2 = v2;

    return ((*p1)->need - (*p2)->need) - ((*p2)->need - (*p1)->need);
}

int main(int argc, char **argv)
{
    stage2 mainArray[] = {
        {8}, {3}, {5}, {1}, {19}, {-2}, {8}, {0},{0}, {4}, {5}, {1}, {8}
    };
    int structAmount = sizeof(mainArray) / sizeof(*mainArray);

    int i;

    stage2 **array = malloc(structAmount * sizeof(*array));

    // Assign pointers
    for (i = 0; i < structAmount; i++) {
        array[i] = &mainArray[i];
    }

    qsort(array, structAmount, sizeof(*array), needS);

    puts("Original");
    for (i = 0; i < structAmount; i++) {
        printf("%d\n", mainArray[i].need);
    }

    puts("");
    puts("Sorted");
    for (i = 0; i < structAmount; i++) {
        printf("%d\n", array[i]->need);
    }

    free(array);

    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM