我有一个txt文件,我只想获得大于12个字符的行。 将这些行插入名为graph_node的图形变量中。
txt文件:
1,"execCode(workStation,root)","OR",0 2,"RULE 4 (Trojan horse installation)","AND",0 3,"accessFile(workStation,write,'/usr/local/share')","OR",0 4,"RULE 16 (NFS semantics)","AND",0 5,"accessFile(fileServer,write,'/export')","OR",0 6,"RULE 10 (execCode implies file access)","AND",0 7,"canAccessFile(fileServer,root,write,'/export')","LEAF",1 6,7,-1
图节点类型:
#ifndef Graph_Structure #define Graph_Structure struct Graph_Node{ char id[50]; char node_name[50]; struct Graph_Node* next; struct Graph_Node* edges; }; typedef struct Graph_Node graph_node; #endif
这是将数据插入图形变量的方法:
void insert_node(graph_node** node, graph_node* data){ printf("nINSERTINGn"); graph_node* temp = (graph_node*)malloc(sizeof(graph_node)); for(int i = 0; i id); i++) temp->id[i] = data->id[i]; for(int i = 0; i node_name) - 1; i++) temp->node_name[i] = data->node_name[i]; temp -> next = *node; *node = temp; }
这是使txt文件中的行大于12个字符的方法:
void generate_nodes(graph_node** graph, char* file_name){ graph_node* data = (graph_node*)malloc(sizeof(graph_node)); FILE* f_Data_Pointer = fopen(file_name, "r"); FILE* f_Aux_Pointer = fopen(file_name, "r"); char c = 0; char line[256]; int counter = 0; int q = 0; //quotation marks bool jump_line = false; while(!feof(f_Data_Pointer)){ c = 0; memset(line, 0, sizeof(line)); while(c != 'n' && !feof(f_Aux_Pointer)){ // check line c = fgetc(f_Aux_Pointer); line[counter] = c; counter++; } if(strlen(line) > 12){ //lines with no edges /*line[counter-3] != '-' && line[counter-2] != '1'*/ int size = strlen(line); printf("nline size: %dn", size); counter = 0; c = 0; while(c != ','){ //id c = fgetc(f_Data_Pointer); if(c != ','){ data->id[counter] = c; counter++; } printf("%c", c); } counter = 0; c = 0; while(1){ //node_name c = fgetc(f_Data_Pointer); if(c != '"'){ data->node_name[counter] = c; counter++; } else{ q++; } if(q > 1 && c == ',') break; printf("%c", c); } counter = 0; c = 0; while(c != 'n'){ c = fgetc(f_Data_Pointer); printf("%c", c); } insert_node(graph, data); memset(data->id, 0, sizeof(data->id)); memset(data->node_name, 0, sizeof(data->node_name)); } else{ //lines with edges while(c != 'n' && !feof(f_Data_Pointer)){ c = fgetc(f_Data_Pointer); } } } fclose(f_Data_Pointer); fclose(f_Aux_Pointer); }
我在“strlen”中的命令“for”中获取insert方法中的错误,它表示data-> id和data-> node_name未初始化但我不明白为什么。 我在数据上使用了malloc:
graph_node* data = (graph_node*)malloc(sizeof(graph_node));
错误:
Conditional jump or move depends on uninitialised value(s) ==3612== at 0x4C30B18: strcpy (vg_replace_strmem.c:510) ==3612== by 0x4008B2: insert_node (mulval.c:44) ==3612== by 0x400C03: generate_nodes (mulval.c:159) ==3612== by 0x400CE8: main (mulval.c:187)
你的代码中最大的问题是你经常忽略' '
终止字节并传递给像strlen
这样的函数,它需要一个有效的字符串(一个以0结尾的字符串)。
例如在insert_node
:
for(int i = 0; i < strlen(data->id); i++) temp->id[i] = data->id[i];
在这里你要复制所有字符,期望' '
终止字节, temp->id
将存储一系列字符,但它不是字符串。 strlen(data->id)
将具有未定义的行为,因为如果在没有0终止字符串的情况下初始化它,则data->id
很可能不会以0结尾。
如果你知道源字符串长度小于49个字符,那么你应该使用strcpy
,或者strncpy
要完全确定:
strncpy(temp->id, data->id, sizeof temp->id); temp->id[sizeof(temp->id) - 1] = 0;
与node_name
相同。 另外,您不检查malloc
返回NULL
。
foef
行也是错误的,请参阅为什么while(!foef(...))
总是错误的 。
你应该改写这个
while(c != 'n' && !feof(f_Aux_Pointer)){ // check line c = fgetc(f_Aux_Pointer); line[counter] = c; counter++; }
像这样:
int c; // <-- not char c while((c = fgetc(f_Aux_Pointer)) != 'n' && c != EOF) line[counter++] = c; line[counter] = 0; // terminating the string!
fgetc
返回一个int
,而不是一个char
,它应该是int
,否则与EOF
的比较会出错。 在这里你忽略了设置0终止字节,结果是一个字符序列,但不是字符串。 下一行if(strlen(line) ...
溢出因为这个,因为strlen
将继续寻找超出限制的0终止字节。对于我来说,为什么你甚至检查EOF
是不清楚的,因为你会继续阅读外部while
循环恢复。如果f_Aux_Pointer
到了最后,该函数不应该返回吗?我不确定你在那里做什么。另外没有策略说明换行符不在前49个读取字符中我认为你应该在这里重新考虑你的策略。
这样做也会更容易:
if(fgets(line, sizeof line, f_Aux_Pointer) == NULL) { // error handling return; // perhaps this? } line[strcspn(line, "n")] = 0; // removing the newline if(strlen(line) > 12) ...
这里
while(c != ','){ //id c = fgetc(f_Data_Pointer); if(c != ','){ data->id[counter] = c; counter++; } printf("%c", c); }
你有与上面相同的错误,你永远不会设置 0-终止字节。 在结束的while
你应该有data->id[counter] = 0;
。 在下一个while
循环中同样的事情。
在generate_nodes
您不需要为时间graph_node
对象分配内存,因为insert_node
无论如何都会创建一个副本。 你可以做:
graph_node data; ... data.id[counter] = c; ... data.node_name[counter] = c; ... insert_node(graph, &data); data.id[0] = 0; data.node_name[0] = 0;
而且你会担心一个malloc
。
编辑
因为您的ID始终是数字的,所以我将结构更改为:
struct Graph_Node{ int id; char node_name[50]; struct Graph_Node* next; struct Graph_Node* edges; };
这将使生活更轻松。 如果您的条件为真,只有您需要的行超过12个字符,并且您感兴趣的行总是具有相同的格式(逗号之间没有空格,第二列始终是引号),就像您在答案中发布的那样然后你可以像这样解析它:
int generate_nodes(graph_node **graph, const char *file_name) { if(file_name == NULL || graph == NULL) return 0; // return error // no need to allocate memory for it // if the insert_node is going to make a // copy anyway struct Graph_Node data = { .next = NULL, .edges = NULL }; FILE *fp = fopen(file_name, "r"); if(fp == NULL) { fprintf(stderr, "Error opening file %s: %sn", file_name, strerror(errno)); return 0; } // no line will be longer than 1024 // based on your conditions char line[1024]; size_t linenmr = 0; while(fgets(line, sizeof line, fp)) { linenmr++; // getting rid of the newline line[strcspn(line, "n")] = 0; if(strlen(line) <= 12) continue; // resume reading, skipt the line char *sep; long int id = strtol(line, &sep, 0); // assuming that there is not white spaces // before and after the commas if(*sep != ',') { fprintf(stderr, "Warning, line %lu is malformatted, ',' exepctedn", linenmr); continue; } data.id = id; // format is: "....", if(sep[1] != '"') { fprintf(stderr, "Warning, line %lu is malformatted, "", exepctedn", linenmr); continue; } // looking for ", char *endname = strstr(sep + 2, "","); if(endname == NULL) { fprintf(stderr, "Warning, line %lu is malformatted, " ", exepctedn", linenmr); continue; } // ending string at ", // easier to do strcnpy *endname = 0; strncpy(data.node_name, sep + 2, sizeof data.node_name); data.node_name[sizeof(data.node_name) - 1] = 0; insert_node(graph, &data); } fclose(fp); return 1; }
现在有趣的是这些:
char *sep; long int id = strtol(line, &sep, 0); // assuming that there is not white spaces // before and after the commas if(*sep != ',') { fprintf(stderr, "Warning, line %lu is malformatted, ',' exepctedn", linenmr); continue; }
strtol
是一个将字符串中的数字转换为实际整数的函数。 此函数优于atoi
,因为它允许您转换不同基数的数字,从二进制到hex。 第二个优点是它告诉你它停止阅读的位置。 这对于错误检测非常有用,我使用这个方法来检测该行是否具有正确的格式。 如果该行具有正确的格式,则必须在数字旁边显示逗号,
我检查这一点,如果不是这样,我打印错误消息并跳过该行并继续读取该文件。
下一个if
检查下一个字符是否是引号"
,因为根据你的文件,第二个参数用引号括起来。遗憾的是,参数的separtor是一个逗号,它也被用作字符串中的普通字符。这使得事情有点复杂(你不能在这里使用strtok
)。再一次,我假设整个论点以",
结尾。 请注意,这不会考虑转义引号。 像这样的一行:
3,"somefunc(a,b,"hello",d)","OR",0
会被错误地解析。 当",
找到时,我将引号设置为' '
以便更容易使用strncpy
,否则我将不得不计算字符串的长度,检查它的长度是否超过目标大小等等如果你需要继续解析, endname + 1
应该指向下一个逗号,否则格式错误。
strncpy(data.node_name, sep + 2, sizeof data.node_name); data.node_name[sizeof(data.node_name) - 1] = 0;
在这里我复制字符串。 源是sep + 2
,因为sep
指向第一个逗号,所以你必须跳过它。 下一个字符是引号,所以你也必须跳过它,因此sep + 2
。 因为名称的长度是未知的,所以最好使用strncpy
,这样可以确保不会写入超出需要的字节数。
最后一步是将节点插入图表中。 请注意,我没有分配内存,因为我知道insert_node
无论如何都要创建一个新的副本。 因为data
只是临时使用,所以不需要分配内存,只需将指针传递给data
(通过传递&data
)到insert_node
。
我用虚拟graph
和虚拟insert_node
测试了这个函数,它只打印节点:
void insert_node(graph_node** node, graph_node* data) { printf("ID: %d, node_name: %sn", data->id, data->node_name); }
这是输出:
ID: 1, node_name: execCode(workStation,root) ID: 2, node_name: RULE 4 (Trojan horse installation) ID: 3, node_name: accessFile(workStation,write,'/usr/local/share') ID: 4, node_name: RULE 16 (NFS semantics) ID: 5, node_name: accessFile(fileServer,write,'/export') ID: 6, node_name: RULE 10 (execCode implies file access) ID: 7, node_name: canAccessFile(fileServer,root,write,'/export')
现在,如果您使用此代码并且不断获得valgrind错误,那么这意味着您仍未在代码的其他部分中出现错误,而这些部分尚未向我们展示。
以上就是c/c++开发分享为什么我在下面的代码中出现分段错误?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/522408.html