Dynamic memory allocation in C problem
I'm trying to increase memory of a, but realloc doesnt seem to do anything. At 4th number program crashes. It seems also that numbers are put into a[0] even though counter is increased and should be a[counter]. I know I start at a[1], because I'm writing counter itself in a[0] when I'm done inputing.
Translation of printf: Input vector (you end input with any nonnumber character except dot).
#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);
}
output:
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
edit: Thank you. Very good answers from all of you.
Is there any way to find out how much memory space does have vektor a allocated? Later in the code I check with sizeof(a)/sizeof(float) for number of elements in that array which now I understand is incorect. Luckily I have counter stored in a so i know how muc开发者_JS百科h elements i have, but if I wouldn't have that information stored how would I know?
The realloc
is incorrect. You are getting the size of a pointer on your machine, not the size of the allocated space so far.
float *a = (float *) malloc(sizeof(float));
/* .... */
a = realloc(a, (sizeof(a) + sizeof(float)));
So, suppose a float *
occupies 4 bytes. You will always allocate 4 + sizeof(float)
and eventually you'll step outside. You need to keep track of the number of elements and then:
a = realloc(a, sizeof(float) * (el_no + 1));
Of course, a nicer form would be:
a = realloc(a, sizeof(*a) * (el_no + 1));
If you later decide to change the type of a
you'll be safe this way.
Edit
As a side note, calling realloc
for each and every new element might seem like a good deal, but it's slow. You should employ a strategy like "when I run out of space I will double the current used amount" or something in that line.
Whatever you think this:
if (sizeof(a) == sizeof(float)) {
return NULL;
}
Is doing, it isn't.
When you do:
float *a = (float *) malloc(sizeof(float));
...
a = realloc(a, (sizeof(a) + sizeof(float)));
the 'sizeof(a)' is always going to return 4(on 32-bit machine, 8 on 64-bit machines). 'sizeof()' despite its appearance is NOT a function. It's an operator of sorts that gives you the size of the variable. IN this case 'a' is just a pointer. sizeof will not give you the size of what a is pointing at.
What you need to do is keep a length variable that keeps track of the number of floats you have in the block allocated by 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;
a = realloc(a, (sizeof(a) + sizeof(float)));
sizeof(a)
and sizeof(float)
are both constants (for the most part, sizeof(anything)
is a constant). So you're always asking for the same amount of memory here.
Typically you need something along the lines of
a = realloc(a, counter * sizeof(float));
but
- You'll need to check this for off-by-one errors: maybe you'll want
(counter + 1)
instead ofcounter
, or so. - Don't ever use
a = realloc(a, ...)
. Look up howrealloc
reports errors (and what it does with the original memory block in the event of errors) to see why.
See also http://c-faq.com/malloc/realloc.html
In short sizeof(a)
doesn't do what you think it does. The type of a
is *float
so it has a very small size. You need to keep track of the length of the array and multiply that by sizeof(float)
to get the current size.
The error you get means you have a buffer overflow in your heap segment. This is because at line 15 you do:
a = realloc(a, (sizeof(a) + sizeof(float)));
sizeof is a macro function it will be determent at compile time not a runtime you should use the counter to calculate the needed size for a new read. Try something like this:
a = realloc(a, (sizeof(*a) * (counter + 1))); // + one for the counter itself
Also you need to keep in mind that at line 21 you cast your integer (counter) to and float which will cause the counter to wrap and restart with negative value.
#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);
}
Output:
gcc -m32 -O3 -Wall -Wextra -std=c99 test.c && ./a.out
equal: true
value = 822222233
flt = 822222208.000000
(int)flt = 822222208
As you can see your counter will corrupt :)
精彩评论