从二进制文件更新记录(项目的一部分)(分段错误)

时间:2015-01-03 20:57:59

标签: c file-io segmentation-fault malloc binaryfiles

我正在尝试从二进制文件中更改一些信息,但是我遇到了分段错误。我一直试图处理它几个小时。假设有两个队名相同。名字想要改变。但是,我得到了分段错误。 (问题)假设有两个团队名称相同。名字想要改变。但是,我得到了分段错误。感谢所有赞赏的答案。

team_name,   city   ,   stadium  ,fdate, colors
the team is in binary file
manunited,manchester,old_trafford,1878,black-rd
chelsea,london,stamford_bridge,1905,blue-whte
manunited,manchester,old_trafford,1878,black-rd

----------------------------------------
example input

update
update team_name=newcastle,founding_date=2014 in teams where team_name=manunited
----------------------------------------
output
**segmentation fault**
----------------------------------------
new output teams.bin should be
newcastle,manchester,old_trafford,2014,black-rd
chelsea,london,stamford_bridge,1905,blue-whte
newcastle,manchester,old_trafford,2014,black-rd

代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>

int main()
{

    char read_command[12];
    /*      checking insert     */
    char str1[100],str2[5],str3[18],space,str4[100];

    scanf("%s", read_command);

    if(strcmp(read_command,"update") == 0)
    {
        scanf("%s",str3);//read update from input code
        //printf("\nstr3=%s",str3);
        scanf("%s",str4);
        //printf("\nstr4=%s",str4);
        scanf("%c",&space);
            fgets(str1,100,stdin);
            //printf("\nstr1=%s",str1);
            updatefunc(str1,str4);
    }

    return 0;
}
void wherefunc(char *str,char *tag,char *id)
{
    char *token;
    int i=0;
    token = strtok(str,"=");
    strcpy(tag,token);
    token = strtok(NULL,"=");
    strcpy(id,token);
}
void updatefunc(char *str1, char *str2)
{
    FILE *fp;

    char tag[30];     // regard to the input it is team_name
    char id[30];     // regard to the input it is manunited

    /* regard to the input it will change first team_name then founding_date */
    char variablenew[30];
    /* regard to the input it will change first newcastle then 2014 */   
    char valuenew[30];


    char *tokenstr1;
    char *tokenstrnew;

    char *buff;
    buff =  (char*) malloc(strlen(str1) + 1);
    strcpy(buff,str1);
    char *token;

    const char space[2] = " ";
    const char comma[2] = ",";
    char tempstrs[10][100];
    char tempstrsnew[10][30];

    int i = 0, j = 0 ,c, ii;

    tokenstrnew = strtok(str2,comma);
    while (tokenstrnew != NULL)
    {
        //printf("  %s    %d \n",tokenstr1,i);
        strcpy(tempstrsnew[j],tokenstrnew);
        j++;
        tokenstrnew = strtok(NULL,comma);
    }
    //printf("%d      %s           %s",j,tempstrsnew[0],tempstrsnew[1]);


    tokenstr1 = strtok(buff,space);

    while (tokenstr1 != NULL)
    {
        /*      get rid of \n character  bcz of fgets()     */
        int len = strlen(tokenstr1);
        if (len > 0 && tokenstr1[len-1] == '\n') tokenstr1[len-1] = '\0';

        //printf("  %s    %d \n",tokenstr1,i);
        strcpy(tempstrs[i],tokenstr1);
        i++;
        tokenstr1 = strtok(NULL,space);
    }

        wherefunc(tempstrs[3],tag,id);  //every wherefunc to seperate "=" symbols
        //printf("\n\ntag = %s    id = %s",tag,id);
        //printf("\n\n%s",str2);
    if(strcmp(tempstrs[1],"teams") == 0)
    {

        fp=fopen("teams.bin", "rb+");
        if (!fp)
        {
            printf("Unable to open file %s", "teams.bin");
            exit(1);
        }

        teams *t;
        t=(teams*)malloc(sizeof(teams)*1000);
        int x = fread(t, sizeof(teams), 1000, fp);
        t = (teams*)realloc(t,x*sizeof(teams));

        for( ii = 0 ; ii < x ; ii++)
        {         
                if((strcmp(tag,"team_name") == 0) && (strcmp(id,t[ii].team_name) == 0))
                {

                    fread(&t[ii], sizeof(teams), 1, fp);

                    for(c = 0 ; c < j ; c++)
                    {
                        wherefunc(tempstrsnew[c],variablenew,valuenew);

                        if(strcmp(variablenew,"team_name") == 0)
                        {

                            strcpy(t[ii].team_name,valuenew);
                            fseek(fp, ii*sizeof(team), SEEK_SET);
                            fwrite(&t[ii], sizeof(teams), 1, fp);
                        }
                        else if(strcmp(variablenew,"founding_date") == 0)
                        {

                            t[ii].founding_date = atoi(valuenew) ;
                            fseek(fp, ii*sizeof(team), SEEK_SET);
                            fwrite(&t[ii], sizeof(teams), 1, fp);
                        }

                    }

            }

        }

    }
}

gdb结果:

    (gdb) run
Starting program: /home/soner/Desktop/folder/a.out 
update
update team_name=newcastle,founding_date=2014 in teams where team_name=manunited

Program received signal SIGSEGV, Segmentation fault.
__strcpy_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:296
296 ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S: No such file or directory.
(gdb) backtrace
#0  __strcpy_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/strcpy-sse2-unaligned.S:296
#1  0x000000000040fa91 in wherefunc (str=0x7fffffffd7a0 "team_name", 
    tag=0x7fffffffdbd0 "team_name", id=0x7fffffffdbf0 "2014") at seg.c:2321
#2  0x00000000004125b8 in updatefunc (
    str1=0x7fffffffdc90 "in teams where team_name=manunited\n", 
    str2=0x7fffffffdd00 "team_name=newcastle") at seg.c:3357
#3  0x000000000040109a in main () at seg.c:70
(gdb) frame 1
#1  0x000000000040fa91 in wherefunc (str=0x7fffffffd7a0 "team_name", 
    tag=0x7fffffffdbd0 "team_name", id=0x7fffffffdbf0 "2014") at seg.c:2321
2321        strcpy(id,token);
(gdb) frame 2
#2  0x00000000004125b8 in updatefunc (
    str1=0x7fffffffdc90 "in teams where team_name=manunited\n", 
    str2=0x7fffffffdd00 "team_name=newcastle") at seg.c:3357
3357                            wherefunc(tempstrsnew[c],variablenew,valuenew);
(gdb) frame 3
#3  0x000000000040109a in main () at seg.c:70
70              updatefunc(str1,str4);
(gdb) 

2 个答案:

答案 0 :(得分:0)

fread之前,还可以按ftell(等)保存文件位置。
您需要fseek定位fwrite之前存储的内容。


试试这个

fseek(fp, ii*sizeof(team), SEEK_SET);
fwrite(&t[ii], sizeof(teams), 1, fp);

答案 1 :(得分:0)

命令分析示例代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct field_U {
    char *name;
    char *value;
} Field_U;

typedef struct command_U {
    char *order;   //"update"
    char *rec_name;//record name. E.g "teams"
    int n;         //number of update field
    Field_U *field;//field and value pair of char *
    Field_U cond;  //condition a field pair.(one pair)
} Command_U;

void *allocate(size_t size){
    void *p = malloc(size);
    if(!p){
        fprintf(stderr, "malloc error!\n");
        exit(-1);
    }
    return p;
}

char *str_dup(const char *str){
    size_t len = strlen(str);
    char *p = allocate(len+1);
    memcpy(p, str, len+1);
    return p;
}

Command_U *analyze_U(const char *cmd){
    char temp1[128];//order field
    char temp2[32]; //record name
    char temp3[64]; //condition field
    if(3!=sscanf(cmd, "update %127s in %31s where %63s", temp1, temp2, temp3)){
        fprintf(stderr, "update syntax error!\n");
        return NULL;
    }

    Command_U *cmdp = allocate(sizeof(*cmdp));
    int n = 0;
    char *p;
    for(p = temp1; p = strchr(p, '='); ++p){
        ++n;//count order field
    }
    cmdp->n = n;
    cmdp->field = allocate(n*sizeof(Field_U));
    int i;
    p = strtok(temp1, ",");
    for(i=0; i<n; ++i){
        cmdp->field[i].name = str_dup(p);
        p = strchr(cmdp->field[i].name, '=');
        *p++ = '\0';
        cmdp->field[i].value = p;
        p = strtok(NULL, ",");
    }
    cmdp->rec_name  = str_dup(temp2);
    cmdp->cond.name = str_dup(temp3);
    p = strchr(cmdp->cond.name, '=');
    *p++ = '\0';
    cmdp->cond.value = p;
    cmdp->order = "update";
    return cmdp;
}

void drop_U(Command_U *cmd){
    int i;
    for(i=0; i<cmd->n; ++i)
        free(cmd->field[i].name);
    free(cmd->field);
    free(cmd->rec_name);
    free(cmd->cond.name);
    free(cmd);
}

int main(){
    char command[] = "update team_name=newcastle,founding_date=2014 in teams where team_name=manunited\n";
    Command_U *cmd = analyze_U(command);
    if(!cmd) return -1;
    printf("order: %s\nrecord name: %s\n", cmd->order, cmd->rec_name);
    int i;
    for(i=0; i < cmd->n; ++i){
        printf("update field%d: (%s, %s)\n", i+1, cmd->field[i].name, cmd->field[i].value);
    }
    printf("condition field : (%s, %s)\n", cmd->cond.name, cmd->cond.value);
    drop_U(cmd);
    return 0;
}
/* output
order: update
record name: teams
update field1: (team_name, newcastle)
update field2: (founding_date, 2014)
condition field : (team_name, manunited)
*/

要使用Command_U

的示例
int main(){
    char read_command[12];
    char command[256];
    Command_U *cmd;

    scanf("%s", read_command);

    if(strcmp(read_command,"update") == 0){
        fgets(command, sizeof(command),stdin);
        if(cmd = analyze_U(command)){
            updatefunc(cmd);
            drop_U(cmd);
        }
    }

    return 0;
}
void updatefunc(Command_U *cmd){
    if(strcmp(cmd->rec_name, "teams") == 0){
        FILE *fp = fopen("teams.bin", "rb+");
        if (!fp){
            printf("Unable to open file %s", "teams.bin");
            exit(1);
        }

        teams t;
        long savepos;
        while(1){
            savepos = ftell(fp);
            if(0==fread(&t, sizeof(t), 1, fp))//read one record
                break;
            if(strcmp(cmd->cond.name, "team_name")==0 && strcmp(cmd->cond.value, t.team_name) == 0){
                int i;
                for(i = 0 ; i < cmd->n ; i++){
                    if(strcmp(cmd->field[i].name, "team_name") == 0)
                        strcpy(t.team_name, cmd->field[i].value);
                    else if(strcmp(cmd->field[i].name, "founding_date") == 0)
                        t.founding_date = atoi(cmd->field[i].value);
                }
                fseek(fp, savepos, SEEK_SET);
                fwrite(&t, sizeof(t), 1, fp);
                fflush(fp);
            }
        }
        fclose(fp);
    }
}