我有一个应该用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的指针,这会正常工作吗?
答案 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