为什么我在动态内存中得到错误的值?

时间:2015-03-16 12:32:01

标签: c memory dynamic struct

我正在编写一个程序,用于存储带有链接结构的主题列表。该程序从文件中读取主题列表,并创建第一个主题“metatema”,然后创建文件中的主题。 当我在文件中写入4个或5个主题时,它可以正常工作。但是当我写更多主题并打印值时,我得到的值不正确。

以下是我的计划的相关代码:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>

#define BUFFER_SIZE 256


/*   STRUCTS   */
typedef struct user {
    struct  sockaddr * direccion;   /* Dir from user */
    struct  user *  siguiente;      /* Next user node */
};

typedef struct topic {
    char *      nombre;         /* Topic name */
    int numero_usuarios;        /* Number of users */
    struct user *   lista;      /* Pointer to the users list */
    struct topic *  siguiente;  /* Next topic */
};

/* GLOBAL VARs */
int numero_temas = 0;
struct topic * temas;
int tam_topic = 0;
int tam_user = 0;

/* FUNCTIONS */
void leerTemas(char * file);

int main(int argc, char *argv[]) {
    if (argc!=3) {
        fprintf(stderr, "Use: %s port file\n", argv[0]);
        return 1;
    }

    leerTemas(argv[2]);

    /* PRINT VALUES */
    int i=0;
    for(i=0; i<numero_temas;i++){
        printf("TOPIC: %s\tADDRESS: %u",(temas + i*sizeof(struct topic))->nombre,(temas + i*sizeof(struct topic)));
        printf("\tNEXT: %u\tUSERS LIST: %u\t NUM. USERS: %u\n",(temas + i*sizeof(struct topic))->siguiente,
            (temas + i*sizeof(struct topic))->lista, (temas + i*sizeof(struct topic))->numero_usuarios);
    }
    return 0;
}

void leerTemas(char * file){
    int pipefd[2];
    if(pipe(pipefd) == -1){
        perror("pipe");
        exit(1);
    }

    /* CALCULAMOS EL NUMERO DE TEMAS PARA RESERVAR MEMORIA */
    numero_temas = 0;

    switch(fork()){
        case -1:                    // ERROR
            perror("fork");
            exit(1);
        case 0:                     // CHILD (WC)
            close(pipefd[0]);
            close(1);
            dup(pipefd[1]);
            close(pipefd[1]);
            execlp("wc","wc",file,(char *)NULL);
            perror("exec");
            exit(1);
        default:                    // PARENT (GET RESULT FROM WC)
            close(pipefd[1]);
            char buffer[BUFFER_SIZE];   bzero(buffer,BUFFER_SIZE);
            char ntemas[BUFFER_SIZE];   bzero(ntemas,BUFFER_SIZE);
            if(read(pipefd[0],buffer,BUFFER_SIZE) <= 0){
                perror("read");
                exit(1);
            }

            /* GETTING THE NUMBER OF LINES FROM WC */
            int i=0,j=0;
            while(buffer[i] == ' ')         // Pass blank spaces
                i++;
            while(buffer[i] != ' '){
                ntemas[j] = buffer[i];
                i++;
                j++;
            }
            ntemas[j] = '\0';
            numero_temas = atoi(ntemas)+1;  // +1 (metatema)
    }

    /* ALLOCATING TOPICs MEMORY */
    temas = malloc(sizeof(struct topic) * numero_temas);
    bzero(temas,sizeof(struct topic)*numero_temas);

    /* CREATING METATEMA */
    temas->nombre = malloc(sizeof(char)*9);
    strcpy(temas->nombre,"metatema\0");
    temas->siguiente = NULL;
    temas->lista = NULL;
    temas->numero_usuarios = 0;

    /* CREATING TOPICs FROM FILE */
    FILE * f = fopen(file,"r");
    int i;
    char buffer[BUFFER_SIZE];
    for(i = 1; i < numero_temas; i++){
        bzero(buffer,BUFFER_SIZE);
        fgets(buffer,BUFFER_SIZE,f);
        buffer[strlen(buffer)-1] = '\0';    // Remove newline char \n

        (temas + i*sizeof(struct topic))->nombre = malloc(sizeof(char)*(strlen(buffer)+1));
        strcpy((temas+i*sizeof(struct topic))->nombre,buffer);
        (temas + i*sizeof(struct topic))->numero_usuarios = 0;
        (temas + i*sizeof(struct topic))->lista = NULL;
        (temas + i*sizeof(struct topic))->siguiente = NULL;
        (temas + (i-1)*sizeof(struct topic))->siguiente = (temas + i*sizeof(struct topic)); // Link prev topic
    }
}

当我在文件中运行包含5个主题的程序时运行正常:

$ cat topics
topic1
topic2
topic3
topic4
topic5
$ ./a.out 8000 topics
TOPIC: metatema ADDRESS: 31891472   NEXT: 31892496  USERS LIST: 0    NUM. USERS: 0
TOPIC: topic1   ADDRESS: 31892496   NEXT: 31893520  USERS LIST: 0    NUM. USERS: 0
TOPIC: topic2   ADDRESS: 31893520   NEXT: 31894544  USERS LIST: 0    NUM. USERS: 0
TOPIC: topic3   ADDRESS: 31894544   NEXT: 31895568  USERS LIST: 0    NUM. USERS: 0
TOPIC: topic4   ADDRESS: 31895568   NEXT: 31896592  USERS LIST: 0    NUM. USERS: 0
TOPIC: topic5   ADDRESS: 31896592   NEXT: 0 USERS LIST: 0    NUM. USERS: 0

但是,当我设置7个主题(例如)时,我得到了错误的值:

$ cat topics
topic1
topic2
topic3
topic4
topic5
topic6
topic7
$ ./a.out 8000 topics
TOPIC: metatema ADDRESS: 7274512    NEXT: 7275536   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic1   ADDRESS: 7275536    NEXT: 7276560   USERS LIST: 1768976244   NUM. USERS: 33
TOPIC: topic2   ADDRESS: 7276560    NEXT: 7277584   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic3   ADDRESS: 7277584    NEXT: 7278608   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic4   ADDRESS: 7278608    NEXT: 7279632   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic5   ADDRESS: 7279632    NEXT: 7280656   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic6   ADDRESS: 7280656    NEXT: 7281680   USERS LIST: 0    NUM. USERS: 0
TOPIC: topic7   ADDRESS: 7281680    NEXT: 0 USERS LIST: 0    NUM. USERS: 0

而且,当我设置11个主题时,我明白了:

$cat topics
topic1
topic2
topic3
topic4
topic5
topic6
topic7
topic8
topic9
topic0
topicA
$ ./a.out 8000 topics
a.out: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
Abortado

我做错了什么?

1 个答案:

答案 0 :(得分:4)

这是问题

(temas + i*sizeof(struct topic))

编译器会自动为您计算偏移量,即

(temas + i)

是您所需要的,或

((char *)temas + i*sizeof(struct topic))

因为这样编译器不会将i乘以sizeof(struct topic),但在之前的情况下它会使代码实际意味着

((char *)temas + i*sizeof(struct topic)*sizeof(struct topic))

所以你添加的东西比你想要的多得多,你不需要像这样使用指针算法,只需

temas[i]

就足够了。

此外,绝对不需要全局变量,只需将它们作为函数参数传递,全局变量可能会导致很多问题,除非您完全确定需要,否则不应使用它们。