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
}

所以我得到分段错误,我不知道为什么?也许是关于指针的东西。我在第一行指定了该方法崩溃的位置(void fillDirectoryStructs)。

当我编译时,我得到:

Country.c:在“主要”功能中:
Country.c:68: 警告:传递“写”的参数 2 使指针从整数而不进行强制转换
Country.c:84: 警告:传递“写”的参数 2 使指针从整数而不进行强制转换
Country.c:86: 警告:传递“写”的参数 2 使指针从整数不进行强制转换
Country.c:232:2:警告:文件末尾没有换行符

我对指针不太了解,但我必须使用系统调用,所以我不能使用任何FILE *函数(fwrite()等),这就是我使用普通write()read().

当我运行它时,当它到达我刚刚指定的那一点时,我会遇到分段错误。

出于测试目的,我正在尝试打印此

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

而不是写,它在那里崩溃,为什么?我究竟做错了什么?那不应该在我的结构中获得第一个国家的代码吗?谢谢

4

2 回答 2

8

好吧,您需要倾听您的编译器并认真对待它的警告。

这个:

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

是错误的,并会解释警告。该变量nLines具有 type int,但如果您查看 [documentation for write()] 您可以看到第二个参数具有 type void *

因此它将您的整数值解释为指针,并开始读取您无权读取的内存。

你需要:

write(fd2, &nLines, sizeof nLines);

请注意,这sizeof不是一个函数,它仅在参数是类型名称时才需要括号(因为它需要对所讨论的类型进行强制转换表达式,并且强制转换被写为括在括号中的类型名称)。

此外,您需要为 I/O 可能失败的现实做好准备。该write()函数有一个返回值,您应该检查它。

于 2013-01-31T16:55:16.897 回答
1

除了 unwind 指出的严重问题之外,您的代码还有许多其他问题。

这个:

CountryData **countryDataPtr;   // Array of structs

不是一个。_ 一旦分配,它可能是一个指向 structsArray of structs的指针数组。

这个:

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

不写一个实例(更不用说CountryData它们的整个数组)。它采用第一个元素名称的第一个字符的整数值,并将其视为指针,就像您对nLines.

如果你想写第一个元素,它看起来像这样:

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

如果你想编写所有元素,你要么需要一个循环,要么需要一个可以一次性编写的连续结构数组。

于 2013-01-31T17:01:24.270 回答