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

时间:2010-10-13 08:38:05

标签: c

我有一个应该用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行时,它会在尝试执行Job#2时中断。知道为什么吗?

另外:如果我需要维护一组JOB以用于其他功能,我的方法是否正确? JOB ** jobQueue是一个指向JOB的指针数组,JOB * newjob是指向JOB的指针,这会正常工作吗?

6 个答案:

答案 0 :(得分:1)

newjob-&gt; filename是一个狂野指针(没有设置为任何东西),你必须先分配内存才能存储它。

答案 1 :(得分:1)

变化:

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

为:

#include <limits.h>

typedef struct{
    char filename[PATH_MAX];
    int time;
} JOB;

答案 2 :(得分:1)

我想补充一些建议

nJobs = 0;

Globals初始化为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标准),可以提高在代码块开始时声明变量的可读性。

答案 3 :(得分:0)

有关改进代码的其他建议:

  • 你永远不会free() malloced指针。

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

  • 您不要在文件句柄上调用fclose()

答案 4 :(得分:0)

Trasvi,不要忘记你的jobQueue是malloc,只能保存JOB结构的3个实例。但是,您的“while循环”与用户输入的次数相同。

但要回答原始问题,只需在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.

答案 5 :(得分:0)

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 =&gt; text_text_text \ r \ n \ 0aq
' '是此元素上的字符空间值是打印机字符,请参阅ascii

  

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

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

  

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

strcmp的其他解决方案:

  

strdup()函数返回一个指向新字符串的指针,该字符串是字符串s的副本。使用malloc(3)获取新字符串的内存,可以使用free(3)释放。   strndup()函数类似,但只复制最多n个字节。如果s大于n,则仅复制n个字节,并添加终止空字节(&#39; \ 0&#39;)。
  源:strndup