Как правильно распределить объем памяти (с) - PullRequest
0 голосов
/ 30 мая 2019

Я сейчас экспериментирую с C, распределением памяти и общей памятью.Мне нужна помощь, код такой:

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

#include <sys/stat.h>
#include <sys/sem.h>
#include <sys/shm.h>

#include "shared_memory.h"
#include "semaphore.h"
#include "errExit.h"

struct Node {
    int ID;
    char password[10];
    struct Node *next;
};

key_t shmKeyServer = 131;
size_t size = (sizeof(struct Node)) * 100;

int main (int argc, char *argv[]) {
    int shmidServer = alloc_shared_memory(shmKeyServer, size);
    struct Node *node = (struct Node *)get_shared_memory(shmidServer, 0);

    //fill all the structs

    for(int i=0;i<100;i++){
       node->ID = i;
       sprintf(node->password, "%s%i", "campo num:", i);
       node->next = node + sizeof(struct Node);
       printf("you are on %i cicle \n", i);
       node = node->next;
    }

    return 0;
}

Функция alloc_shared_memory здесь:

int alloc_shared_memory(key_t shmKey, size_t size) {
   // get, or create, a shared memory segment
   int shmid = shmget(shmKey, size, IPC_CREAT | S_IRUSR | S_IWUSR);
   if (shmid == -1)
       errExit("shmget failed");

   return shmid;
}

get_shared_memory:

void *get_shared_memory(int shmid, int shmflg) {
    // attach the shared memory
    void *ptr_sh = shmat(shmid, NULL, shmflg);
    if (ptr_sh == (void *)-1)
        errExit("shmat failed");

    return ptr_sh;
}

Проблемаэто после 8-го цикла.Я получаю ошибку сегментации.Я думаю, что проблема заключается в распределении памяти или объявлении размера.

1 Ответ

1 голос
/ 30 мая 2019

Проблема в строке:

node->next = node + sizeof(struct Node);

Поскольку typeof(node) равно struct Node *, этот оператор увеличивает указатель node на sizeof(struct Node) * sizeof(struct Node) байт (см. Арифметику указателей в C). Вы хотите увеличить указатель node на sizeof(struct Node) байтов, а не на sizeof(struct Node) узлов.

Вы хотите:

node->next = (char*)node + sizeof(struct Node);
// or better:
node->next = (void*)((uintptr_t)(void*)node + sizeof(struct Node));
node->next = (void*)((char*)(void*)node + sizeof(struct Node));
// or 
node->next = node + 1;
node->next = &node[1];

Который исправляет ошибку сегмента.

В строке:

sprintf(node->password, "%s%i", "campo num:", i);

происходит неопределенное поведение. "%s%i", "campo num:", i печатает 12 байтов в node->password указатель, который имеет только 10 байтов памяти:

campo num:1

- 11 символов + 1 байт для строки, заканчивающейся нулевым байтом. Также для чисел, больших 10 sprintf, будет записано 13 байтов. Лучше использовать snprintf как в snprintf(node->password, sizeof(node->password) для защиты от переполнения буфера. Также вы можете sprintf возвращаемое значение int ret = sprintf(..); if (ret > sizeof(node->password)) { err(1, "Overflowed"); }

...