I can't tell what options you ran valgrind with. The leak checker runs in summary mode by default, so you should have seen something like
Code:
==12190== HEAP SUMMARY:
==12190== in use at exit: 104 bytes in 7 blocks
==12190== total heap usage: 13 allocs, 6 frees, 141 bytes allocated
==12190==
==12190== LEAK SUMMARY:
==12190== definitely lost: 64 bytes in 4 blocks
==12190== indirectly lost: 0 bytes in 0 blocks
==12190== possibly lost: 0 bytes in 0 blocks
==12190== still reachable: 40 bytes in 3 blocks
==12190== suppressed: 0 bytes in 0 blocks
==12190== Rerun with --leak-check=full to see details of leaked memory
Which instructs you to use the --leak-check=full option, which would give you a backtrace of the functions that lead to a malloc without a free
Code:
==12191== 64 bytes in 4 blocks are definitely lost in loss record 3 of 3
==12191== at 0x4006D69: malloc (vg_replace_malloc.c:236)
==12191== by 0x80485B1: createSensor (foo.c:19)
==12191== by 0x804865F: checkSerialHart (foo.c:33)
==12191== by 0x80486A5: pollHart (foo.c:48)
==12191== by 0x80487B9: main (foo.c:77)
So yes you leak memory. You leak the malloc call in createSensor.
That conditional jump issue on line 64 is the sprintf(wholeMsg + strlen(wholeMsg), ...). That needs to be fixed, it's undefined behavior. You're relying on wholeMsg having a null character in the first position, which it might not, since it's an uninitialized automatic variable. That could technically be the cause of your problem, but it's probably not.
Adding your new free code, I get:
Code:
$ valgrind --leak-check=full ./foo
==12228== Memcheck, a memory error detector
==12228== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==12228== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==12228== Command: ./foo
==12228==
==12228== Conditional jump or move depends on uninitialised value(s)
==12228== at 0x8048765: sendToIridium (foo.c:64)
==12228== by 0x804881C: main (foo.c:82)
==12228==
address: 0, current: 3.000000, pressure: address: 10000, current: 4.000000, pressure:
==12228== Invalid free() / delete / delete[]
==12228== at 0x4006E53: realloc (vg_replace_malloc.c:525)
==12228== by 0x804862E: checkSerialHart (foo.c:30)
==12228== by 0x80486D5: pollHart (foo.c:48)
==12228== by 0x8048817: main (foo.c:81)
==12228== Address 0x40270e0 is 0 bytes inside a block of size 8 free'd
==12228== at 0x4005ECD: free (vg_replace_malloc.c:366)
==12228== by 0x8048829: main (foo.c:83)
==12228==
==12228==
==12228== HEAP SUMMARY:
==12228== in use at exit: 0 bytes in 0 blocks
==12228== total heap usage: 6 allocs, 6 frees, 57 bytes allocated
==12228==
==12228== All heap blocks were freed -- no leaks are possible
==12228==
==12228== For counts of detected and suppressed errors, rerun with: -v
==12228== Use --track-origins=yes to see where uninitialised values come from
==12228== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 39 from 8)
That tells me there is an issue with the realloc, but only on the second iteration (note the first successful print of wholeMsg). That means, you screw something up in/after the first free. When you free sensors, it still contains the old memory address from realloc, but the memory there is no longer valid. You then pass that address to realloc, but that address is no longer an alloc'ed address, yet it seems you still try to free sensors[i] and sensors at that address, which have already been freed. Unfortunately, I have to run and can't finish this up.
NOTE: I seriously think you don't need any memory allocation in this program at all. Declare an array with the max number of sensors you'll have, and simply use sensor_count to tell you how many spots in the array are in use. It is functionally equivalent to what you're doing, wastes very little memory (3 sensors), and is free from these problems you're having.