0
// Struct for Country Data
typedef struct
{
    char name[50];          // Country name
    char code[3];           // Country code
    int population;         // Country Population
    double lifeExp;         // Country Life expectancy  

}   CountryData;

// Struct for Dir File
typedef struct
{
    char code[3];
    int offSet;

}   DirData;

// Function Declarations
void fillCountryStructs(CountryData ** dataPtr, int nLines, int fd);
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines,int fd2);
void sortStructs(DirData **director, int nLines);
int verifyString(char *s1, char *s2);

// Main Function
// - This function starts the program, get the number of lines as a 
//   parameter, fills the structs and writes the data to the Country
//   File and the Directory file.
int main(int argc, char *argv[])        // Always remember to pass an argument while executing
{
    // Some variables
    int nLines;             // The number of lines
    char *pEnd;             // For String functions
    FILE *Fin,*Fout;        // File pointers
    int fd; 
    int fd2;
    nLines = strtod(argv[1], &pEnd); 
    CountryData **countryDataPtr;   // Array of structs
    CountryData **tempStruct;
    DirData **director;

    // Allocate memory for the struct pointers
    countryDataPtr = calloc(nLines, sizeof(CountryData*));
    director = calloc(nLines, sizeof(DirData*));

    // File Stream for "AllCountries.dat"
    if((fd = open("AllCountries.dat", O_RDWR)) ==-1)
        err_sys("File not found...\n");
    // File Stream for "RandomStruct.bin"
    if ((fd2 = open("RandomStruct.bin", O_RDWR)) == -1) 
        err_sys("Failed to open binary\n");

    // Filling the Country stucts
    fillCountryStructs(countryDataPtr, nLines, fd);
    close (fd);
    //fclose(Fin);                                      // Closing the file "AllCountries.dat"
    // Writing Binary File
    write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));
    close (fd2);
    //fclose(Fout);
    printf("RandomStruct.bin written Sucessfully\n");

    // Filling the Directory File
    // File Stream for "RandomStructDir.dir"
    if ((fd2 = open("RandomStructDir.dir",O_RDWR|O_TRUNC)) != -1) 
        err_sys("Failed to open binary\n");

    fillDirectoryStructs(countryDataPtr, director, nLines, fd2);
    sortStructs(director, nLines);                                  // Sorting the structs

    // Write the number of lines in the FIRST LINE
    // of the Directory File
    write(fd2, nLines, sizeof(nLines));
    // Writing Directory File after the number of lines was written
    write(fd2,(director[0]->code[0]), sizeof(DirData));
    close (fd2);
    //fclose(Fout);
    printf("RandomStructDir.dir written Sucessfully\n\n");

    exit(0);
}

// Filling the Country structs
// - This function extracts the data from the file using strtok 
//   and fills all the structs with their corresponding values.
void fillCountryStructs(CountryData **dataPtr, int nLines, int fd)
{
    int curLine = 0;        // Current line
    int index = 0;          // The index
    char buf[BUFSIZE];      // The Buffer with the size of BUFSIZE
    char *tok;              // Token
    char *pEnd;             // For the String functions
        char ch = 'a'; // The temp character
    int temPop;
    double temLifeExp;  
    int num=0;

    for(curLine = 0; curLine < nLines; curLine++)
    {
       // Reading each line
    dataPtr[curLine] = (CountryData *)calloc(1, sizeof(CountryData));
    index = 0;
    do
    {
    read(fd, &ch, 1);
    buf[index++] = ch;
    }
    while(ch != '\n');

        // Strtoking...
        tok = strtok(buf, ",\n");

        index = 1;
        while(tok != NULL)
        {
            tok = strtok(NULL, ",\n");

            // Get the Country Code
            if(index == 1)
            {
                strcpy(dataPtr[curLine]->code, tok);        // Copying code to the struct
            }
            // Get the Country Name
            if(index == 2)
            {
                strcpy(dataPtr[curLine]->name, tok);        // Copying name to the struct
            }
            // Get the Country Population
            if(index == 7)
            {
                temPop = (int)strtol(tok, &pEnd, 10);
                dataPtr[curLine]->population = temPop;      // Copying population to the struct
            }
            // Get the Country Life expectancy
            if(index == 8)
            {
             num=countchar(tok);
          printf ("The number of characters entered is %d\n", num);
          printf ("The character entered is %s\n",tok);
                temLifeExp = strtod(tok, &pEnd);
                dataPtr[curLine]->lifeExp = temLifeExp;     // Copying life expectancy to the struct
            }
            index++;
        }
    }
}


int countchar (char list[])
{
        int i, count = 0;
        for (i = 0; list[i] != '\0'; i++)
        count++;
        return (count);
}



// Filling the Directory Structs
// - This function fills the directory with the offset
void fillDirectoryStructs(CountryData **dataPtr, DirData **director, int nLines, int fd2)
{

    int i = 0;
    for(i = 0; i < nLines; i++)
    {
        strcpy(director[i]->code, dataPtr[i]->code);      //It crashes in this Line
        director[i]->offSet = sizeof(CountryData) * (i);        
    }   
}

// Sorting the Dir Structs
// - This function sorts the Directory Structs.
void sortStructs(DirData **director, int nLines)
{

    int maxNumber;
    int i;
    DirData **temp;
    temp = calloc(1, sizeof(DirData));

    // Sorting the array of pointers!
    for(maxNumber = nLines - 1; maxNumber > 0; maxNumber--)
    {
        for(i = 0; i < maxNumber; i++)
        {
            if((verifyString(director[i]->code, director[i+1]->code)) == 1)
            {
                temp[0] = director[i];
                director[i] = director[i+1];
                director[i+1] = temp[0];
            }           
        }           
    }
}

// Veryfying the strings
// - This function compares two strings and return a specific value
//   accordingly.
int verifyString(char *s1, char *s2)
{
    int i;
    if(strcmp(s1,s2) == 0)
        return(0);          // They are equal

    for(i = 0; s1[i] != 0; i++)
    {
        if(s1[i] > s2[i])
            return(1);              // s1 is greater
        else if(s1[i] < s2[i])
            return(2);              // s2 is greater
    }

    return (2); // s2 is greater
}

だから私はセグメンテーション違反になります、そして私はなぜか分かりませんか?多分ポインタについての何かです。最初の行で、クラッシュする場所(fillDirectoryStructsを無効にする)を指定しました。

コンパイルすると、次のようになります。

Countries.c:関数'main'内:
Countries.c:68:警告:「write」の引数2を渡すと、キャストなしで整数からポインターが作成されます
Countries.c:84:警告:「write」の引数2を渡すと、キャストなしで整数からポインターが作成されます
Countries.c:86:警告:「write」の引数2を渡すと、キャストなしで整数からポインターが作成されます
Countries.c:232:2:警告:ファイルの終わりに改行がありません

ポインタについてはよくわかりませんが、システムコールを使用する必要があるため、FILE *関数(fwrite()など)を使用できません。そのため、plainwrite()とを使用していread()ます。

実行すると、指定したポイントに到達するとセグメンテーション違反が発生します。

テスト目的でこれを印刷しようとしています

printf("test: %s\n", countryDataPtr[0]->code[0]);

書く代わりに、そこでクラッシュします、なぜですか?私は何が間違っているのですか?それは私の構造でその最初の国のコードを取得するべきではありませんか?ありがとう

4

2 に答える 2

8

さて、あなたはあなたのコンパイラに耳を傾け、その警告を真剣に受け止める必要があります。

これ:

write(fd2, nLines, sizeof(nLines));

間違っており、警告を説明します。変数のnLinesintはですが、[ドキュメント write()]を見ると、2番目の引数の型が。であることがわかりますvoid *

したがって、整数値をポインタとして解釈し、読み取る権利のないメモリの読み取りを開始します。

必要なもの:

write(fd2, &nLines, sizeof nLines);

これは関数ではないことに注意してくださいsizeof。引数が型名の場合にのみ括弧が必要です(問題の型へのキャスト式が必要であり、キャストは括弧で囲まれた型名として書き込まれるため)。

また、I/Oが失敗する可能性があるという現実に備える必要があります。write()関数には、チェックする必要のある戻り値があります。

于 2013-01-31T16:55:16.897 に答える
1

深刻な問題が指摘されていることに加えて、コードには他にも多くの問題があります。

これ:

CountryData **countryDataPtr;   // Array of structs

ではありませArray of structs。割り当てられると、構造体へのポインタの配列になる可能性があります。

これ:

write(fd2, (countryDataPtr[0]->name[0]), sizeof(CountryData));

1つのインスタンスを書き込みませCountryData(ましてやそれらの配列全体)。これは、最初の要素の名前の最初の文字の整数値を取り、それを。の場合と同じようにポインターとして扱いますnLines

最初の要素を記述したい場合は、次のようになります。

write(fd2, countryDataPtr[0], sizeof(CountryData));

また、すべての要素を記述したい場合は、ループか、一度に記述できる構造体の連続した配列が必要になります。

于 2013-01-31T17:01:24.270 に答える