C程序指针崩溃系统调用

use*_*697 0 c pointers system

// 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
}
Run Code Online (Sandbox Code Playgroud)

所以我得到分段错误,我不明白为什么?也许是关于指针的东西.我指定了第一行崩溃的地方(void fillDirectoryStructs).

当我编译时,我得到:

Countries.c: In function 'main':
Countries.c:68: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:84: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:86: warning: passing argument 2 of 'write' makes pointer from integer without a cast
Countries.c:232:2: warning: no newline at end of file

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

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

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

printf("test: %s\n", countryDataPtr[0]->code[0]);
Run Code Online (Sandbox Code Playgroud)

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

unw*_*ind 8

好吧,你需要听取你的编译器并认真对待它的警告.

这个:

write(fd2, nLines, sizeof(nLines));
Run Code Online (Sandbox Code Playgroud)

是错的,并会解释警告.变量nLines有类型int,但是如果你查看[documentation for write()],你可以看到第二个参数有类型void *.

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

你需要:

write(fd2, &nLines, sizeof nLines);
Run Code Online (Sandbox Code Playgroud)

请注意,这sizeof不是一个函数,它只需要在参数是类型名称时需要括号(因为它需要一个强制转换表达式来表示相关类型,并且强制转换被写为括在括号中的类型名称).

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