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

标签 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

我做错了什么?

最佳答案

这就是问题所在

(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]

就足够了。

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

关于c - 为什么我在动态内存中得到错误的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29076887/

相关文章:

c - putc() 在通过 popen 打开的管道发送数据时会阻塞

c - 为什么这个内存地址改变了

c - 节点->指针=指针与使用memcpy的节点->指针

python - 如何让我的 Python 程序使用 4 个字节而不是 24 个字节来表示 int?

c - dmalloc 提供返回地址信息显示 `unknown' ?

c - 什么是 MsgPack 'zone'

c - 如何有效地构建 C 程序

c++ - C++中动态二维数组中的地址

c - 链表 createList 与 initNode 函数

c++ - 将动态二维数组的返回指针传递给子函数并寻址该数组