Динамическое распределение памяти в задаче C - PullRequest
1 голос
/ 13 мая 2011

Я пытаюсь увеличить память, но realloc, похоже, ничего не делает. На 4-м номере программа вылетает. Кажется также, что числа помещаются в [0], даже если счетчик увеличен и должен быть [счетчиком]. Я знаю, что начинаю с [1], потому что пишу сам счетчик в [0], когда я закончу ввод.

Перевод printf: вектор ввода (ввод заканчивается любым нечисловым символом, кроме точки).

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

typedef float* vektor;

vektor beriVektor() {
    int counter = 0;
    float zacasna;
    float *a = (float *) malloc(sizeof(float));
    printf("Vpisi vektor (vpis zakljucis s katerim koli nestevilskim znakom razen pike):\n");
    while(scanf("%f", &zacasna)) {
        counter++;
        printf("%d\n", counter);
        printf("%d\n", sizeof(a));
        a = realloc(a, (sizeof(a) + sizeof(float)));
        a[counter] = zacasna;
    }
    if (sizeof(a) == sizeof(float)) {
        return NULL;
    }
    a[0] = counter;
    return a;
}

void izpisiVektor(vektor a) {
    if (a == NULL) {
        return;
    }
    else {
        int velikost = sizeof(a)/sizeof(float);
        for (int i = 0; i < velikost; i++) {
            printf("%f", *(a+i));
        }
    }

}

void main(){
    vektor a = beriVektor();
    izpisiVektor(a);

}

выход:

ragezor@ragezor-VirtualBox:~$ ./dn09.o 
Vpisi vektor (vpis zakljucis s katerim koli nestevilskim znakom razen pike):
1 2 3 4
1
4
2
4
3
4
4
4
*** glibc detected *** ./dn09.o: realloc(): invalid next size: 0x09052008 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0x835501]
/lib/libc.so.6(+0x71c6d)[0x83ac6d]
/lib/libc.so.6(realloc+0xe3)[0x83af53]
./dn09.o[0x804850e]
./dn09.o[0x8048595]
/lib/libc.so.6(__libc_start_main+0xe7)[0x7dfce7]
./dn09.o[0x8048411]
======= Memory map: ========
001c9000-001e3000 r-xp 00000000 08:01 393295     /lib/libgcc_s.so.1
001e3000-001e4000 r--p 00019000 08:01 393295     /lib/libgcc_s.so.1
001e4000-001e5000 rw-p 0001a000 08:01 393295     /lib/libgcc_s.so.1
005d5000-005f1000 r-xp 00000000 08:01 393234     /lib/ld-2.12.1.so
005f1000-005f2000 r--p 0001b000 08:01 393234     /lib/ld-2.12.1.so
005f2000-005f3000 rw-p 0001c000 08:01 393234     /lib/ld-2.12.1.so
0069e000-0069f000 r-xp 00000000 00:00 0          [vdso]
007c9000-00920000 r-xp 00000000 08:01 393454     /lib/libc-2.12.1.so
00920000-00922000 r--p 00157000 08:01 393454     /lib/libc-2.12.1.so
00922000-00923000 rw-p 00159000 08:01 393454     /lib/libc-2.12.1.so
00923000-00926000 rw-p 00000000 00:00 0 
08048000-08049000 r-xp 00000000 08:01 140607     /home/ragezor/dn09.o
08049000-0804a000 r--p 00000000 08:01 140607     /home/ragezor/dn09.o
0804a000-0804b000 rw-p 00001000 08:01 140607     /home/ragezor/dn09.o
09052000-09073000 rw-p 00000000 00:00 0          [heap]
b7700000-b7721000 rw-p 00000000 00:00 0 
b7721000-b7800000 ---p 00000000 00:00 0 
b78d9000-b78da000 rw-p 00000000 00:00 0 
b78e7000-b78eb000 rw-p 00000000 00:00 0 
bfc2e000-bfc4f000 rw-p 00000000 00:00 0          [stack]
Aborted

редактирование: Спасибо. Очень хорошие ответы от всех вас.

Есть ли способ узнать, сколько места в памяти выделено для вектора? Позже в коде я проверяю с помощью sizeof (a) / sizeof (float) количество элементов в этом массиве, которое, как я теперь понимаю, неверно. К счастью, у меня есть счетчик, поэтому я знаю, сколько у меня элементов, но если бы у меня не было этой информации, как бы я узнал?

Ответы [ 6 ]

3 голосов
/ 13 мая 2011

realloc неверно.Вы получаете размер указателя на вашем компьютере, а не размер выделенного пространства.

float *a = (float *) malloc(sizeof(float));
/* .... */
a = realloc(a, (sizeof(a) + sizeof(float)));

Итак, предположим, что float * занимает 4 байта.Вы всегда будете выделять 4 + sizeof(float) и в конце концов выйдете на улицу.Вам необходимо отслеживать количество элементов, а затем:

a = realloc(a, sizeof(float) * (el_no + 1));

Конечно, более приятная форма будет выглядеть следующим образом:

a = realloc(a, sizeof(*a) * (el_no + 1));

Если позже вы решите изменить тип a вы будете в безопасности таким образом.

Редактировать

В качестве примечания , вызывая realloc для каждого нового элементаможет показаться хорошей сделкой, но это медленно.Вам следует использовать такую ​​стратегию, как «когда мне не хватит места, я удвою текущее использованное количество» или что-то в этой строке.

1 голос
/ 13 мая 2011

Когда вы делаете:

 float *a = (float *) malloc(sizeof(float));

 ...
 a = realloc(a, (sizeof(a) + sizeof(float)));

sizeof (a) всегда будет возвращать 4 (на 32-битной машине, 8 на 64-битной). ' sizeof () ', несмотря на его внешний вид, НЕ является функцией. Это своего рода оператор, который дает вам размер переменной. В этом случае «а» это просто указатель. sizeof не даст вам размер того, на что указывает.

Что вам нужно сделать, так это сохранить переменную длины, которая отслеживает количество операций с числами в блоке, выделенных функцией malloc / realloc.

  int N_floats = 0 ;
  float *a = (float *)malloc(0) ;
  /* add a float */

  a = (float *)realloc(a, (N_floats+1)*sizeof(float)) ;
  a[N_floats] = 1.0 ;
  N_floats += 1;
1 голос
/ 13 мая 2011

Что бы вы ни думали об этом:

if (sizeof(a) == sizeof(float)) {
      return NULL;
}

Делает, это не так.

0 голосов
/ 13 мая 2011

Полученная ошибка означает, что в вашем сегменте кучи переполнен буфер. Это потому, что в строке 15 вы делаете:

a = realloc(a, (sizeof(a) + sizeof(float)));

sizeof - это макрофункция, которую она будет сдерживать во время компиляции, а не во время выполнения. Вы должны использовать счетчик для вычисления необходимого размера для нового чтения. Попробуйте что-то вроде этого:

a = realloc(a, (sizeof(*a) * (counter + 1))); // +  one for the counter itself

Также вам следует помнить, что в строке 21 вы приводите свое целое число (счетчик) к значению с плавающей точкой, что приведет к оборачиванию и повторному запуску счетчика с отрицательным значением.

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

int main()
{
    int value = 822222233;
    float flt = value;

    printf("equal: %s\nvalue = %d\nflt = %f\n(int)flt = %d", value == flt ? "true" : "false", value, flt, ((int)flt));

    exit(0);
}

Выход:

gcc -m32 -O3 -Wall -Wextra -std=c99 test.c && ./a.out
equal: true
value = 822222233
flt = 822222208.000000
(int)flt = 822222208

Как видите, ваш счетчик будет поврежден:)

0 голосов
/ 13 мая 2011

Короче говоря sizeof(a) не делает то, что вы думаете, что делает.Тип a - *float, поэтому он имеет очень маленький размер.Вам необходимо отслеживать длину массива и умножать ее на sizeof(float), чтобы получить текущий размер.

0 голосов
/ 13 мая 2011
a = realloc(a, (sizeof(a) + sizeof(float)));

sizeof(a) и sizeof(float) являются константами (по большей части, sizeof(anything) является константой).Таким образом, вы всегда запрашиваете один и тот же объем памяти здесь.

Обычно вам нужно что-то вроде

a = realloc(a, counter * sizeof(float));

, но

  1. Вы будетенеобходимо проверить это на наличие ошибок: возможно, вы захотите (counter + 1) вместо counter или около того.
  2. Не когда-либо используйте a = realloc(a, ...).Посмотрите, как realloc сообщает об ошибках (и что он делает с исходным блоком памяти в случае ошибок), чтобы понять, почему.

См. Также http://c -faq.com /таНос / realloc.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...