代码之家  ›  专栏  ›  技术社区  ›  Trasvi

使用strcpy时C-crash中的结构和指针

c
  •  0
  • Trasvi  · 技术社区  · 15 年前

    我有一个任务,应该用C(不是C++)编写,其中我需要从读取多个文本文件创建一些结构。我在2年前就学会了C语言——我对Java很舒服,只是不能用这个项目。我想我的问题是对指针语法不太了解:/。 然而,我真正的问题是:

    尝试使用strcpy函数时,我编写的代码崩溃:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    typedef struct{
        char* filename;
        int time;
    } JOB;
    
    JOB **jobQueue;
    int nJobs;
    
    void trimLine(char* line) {
        for (int i = strlen(line); i >=0; i--) {
            if (line[i] == '\n' || line[i] == '\r') line[i] = '\0';
        }
    }
    
    int main(int argc, char* argv[]) {
        if (argc !=2) {
            printf("Error - Usage is: my_project file\n");
            exit(-1);
        }
        FILE *fp;
        fp = fopen(argv[1],"r");
        if (fp==NULL) {
            printf("Error - file %s could not be read.\n",argv[1]);
            exit(-1);
        }
        jobQueue = malloc(3*sizeof(JOB*));
        char filename[BUFSIZ];
        nJobs = 0;
        while (fgets(filename,sizeof(jobfilename),fp)!=NULL) {
            trimLine(filename);    
            JOB* newjob;
            newjob = malloc(sizeof(JOB));
                //** THIS IS WHERE IT SCREWS UP
            strcpy(newjob->filename,filename);
    
            jobQueue[nJobs++] = newjob;
        }
    }
    

    如果我删除了包含strcpy的行,程序运行良好(好吧,我意识到这部分实际上没有做任何事情,但仍然如此)。但是,当程序包含strcpy行时,它在尝试执行作业2时中断。你知道为什么吗?

    另外:如果我需要维护一系列用于其他函数的作业,我所做的方法是否正确?job**jobqueue是指向作业的指针数组,job*newjob是指向作业的指针,是否正确?

    6 回复  |  直到 11 年前
        1
  •  1
  •   dutt    15 年前

    newjob->文件名是一个野生指针(不设置为任何内容),必须先分配内存,然后才能在其中存储内容。

        2
  •  1
  •   Paul R    15 年前

    变化:

    typedef struct{
        char* filename;
        int time;
    } JOB;
    

    到:

    #include <limits.h>
    
    typedef struct{
        char filename[PATH_MAX];
        int time;
    } JOB;
    
        3
  •  1
  •   BlueDog    15 年前

    我想增加一些建议

    nJobs = 0;
    

    全局初始化为0,不需要手动执行。

    while (fgets(filename,sizeof(jobfilename),fp)!=NULL) {
    

    您的代码中没有声明JobFileName。我猜你的意思是文件名。

    for (int i = strlen(line); i >=0; i--) {
        if (line[i] == '\n' || line[i] == '\r') line[i] = '\0';
    }
    

    从结尾\0开始,可以跳过。

    您可以在任何地方声明新的变量,这是一个很好的实践(和C89标准),它提高了在代码块开头声明变量的可读性。

        4
  •  0
  •   codymanix    15 年前

    改进代码的其他建议:

    • 你从不 free() 错误的指针。

    • 什么工作超过3个? 您的代码无法处理此问题。你 可以使用 链表 而不是 数组。

    • 你不打电话 fclose() 在您的文件句柄上。

        5
  •  0
  •   Sir Wellington    15 年前

    但要回答最初的问题,只需在strcpy之前将其添加到代码中。

    newjob->filename = malloc ( strlen( filename) +1 );
    //You only need to malloc the amount of characters in the filename + 1,
    //which is for the null-terminated char, and you don't need to worry about 
    //multiplying by 'sizeof' because a char is one byte on any compiler.
    
        6
  •  0
  •   Victor Carrera    11 年前

    您有一个空指针 newjob->filename :

    int nJobsMax=3;
    char* filename;
    JOB* newjob;
    ...
    jobQueue = malloc(nJobsMax*sizeof(JOB*));
    filename=(char*)malloc(BUFSIZ);
    while (fgets(filename,BUFSIZ,fp)!=NULL) {       
        trimLine(filename);        
        newjob = (JOB*)malloc(sizeof(JOB));
        newjob->filename = filename;
        filename=(char*)malloc(BUFSIZ);
        jobQueue[nJobs++] = newjob;
        if (nJobs > nJobsMax) 
            //possible buffer overflow need escape
    
    }
    free(filename);
    fclose(fp);
    

    更多的东西:

    void trimLine(char* line) {
       int i = strlen(line)-1;
       do{
            if (line[i] == '\n' || line[i] == '\r') 
                line[i] = '\0';
        }while(!(line[i]>=' ')||i-->=0);                       
    } 
    

    你真的不需要重复所有的字符串
    示例:fgetd output=>文本\u文本\r\n\0aq
    ' ' 此元素上的字符空间值是否为打印机字符请参见 ascii .

    fgets()从流中最多读取一个小于大小的字符,并将它们存储到s指向的缓冲区中。在eof或换行符之后,读取将停止。如果要读取换行符,它将存储在缓冲区中。终止的空字节(aq \0aq)存储在缓冲区的最后一个字符之后。
    来源: fgets

    strncpy更推荐使用strcpy,因为它可以保护代码不受缓冲区溢出的影响。

    strncpy()函数与之类似,只是最多复制了SRC的n个字节。警告:如果SRC的前n个字节中没有空字节,则dest中的字符串将不会以空结尾。 如果src的长度小于n,strncpy()会向dest写入额外的空字节,以确保总共写入n个字节。
    来源: strncpy

    strcmp的其他解决方案:

    函数的作用是:返回一个指向新字符串的指针,该字符串是字符串s的副本。新字符串的内存是用malloc(3)获得的,可以用free(3)释放。 strndup()函数类似,但最多只能复制n个字节。如果s长于n,则只复制n个字节,并添加一个终止的空字节(“\0”)。
    来源: strndup