I have been programming for a while but I am new to C. I have this linked list implementation in ansi C that I need to test. I have narrowed the problem down to an issue with an invalid write. I ran the code through Valgrind and received the following output:
==18131== Invalid write of size 1
==18131== at 0x4C2C0CC: __GI_strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64 linux.so)
==18131== by 0x40089B: main (in /home/btm7984/hw3/TestList)
==18131== Address 0x51f1388 is 0 bytes after a block of size 8 alloc'd
==18131== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x400880: main (in /home/btm7984/hw3/TestList)
==18131==
==18131== Invalid write of size 1
==18131== at 0x4C2C0DF: __GI_strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x40089B: main (in /home/btm7984/hw3/TestList)
==18131== Address 0x51f138e is 6 bytes after a block of size 8 alloc'd
==18131== at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==18131== by 0x400880: main (in /home/btm7984/hw3/TestList)
==18131==
--18131-- VALGRIND INTERNAL ERROR: Valgrind received a signal 11 (SIGSEGV) - exiting
--18131-- si_code=1; Faulting address: 0x6D4FCAA; sp: 0x402bdae00
All that I can ascertain from this is that I am allocating something wrong. I think it has to be with my strcpy line. I really don't know how to approach this question. What follows is my use of the LinkedLists interface. InitLinkedLists, AddToBackOfList, and DestroyList are all defined in that interface.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "LinkedLists.h"
int main(int argc, char *argv[]) {
FILE *fp;
char tmpString[100];
LinkedLists *ListPtr = malloc(sizeof(LinkedLists));
ElementStructs *DataPtr;
LinkedListNodes* curr = malloc(sizeof(LinkedListNodes));
int counter = 0;
int Done = 0;
InitLinkedList(ListPtr);
fp = fopen(argv[1], "r");
if (!fp){
fprintf(stderr,"%s Cannot open file %s\n", argv[0], argv[1]);
exit(1);
}
do{
fscanf(fp,"%s",tmpString);
if (!feof(fp)) {
DataPtr = malloc(sizeof(DataPtr));
printf("%d %d : %d\n",counter,(int)strlen(DataPtr->str),(int)strlen(tmpString));
strcpy(DataPtr->str,tmpString);
DataPtr->index=counter;
AddToBackOfLinkedList(ListPtr, DataPtr);
counter++;
Done = 1;
} else {
Done = 0;
}
}while (Done);
In conclusion, I think strcpy is causing an invalid write and I don't know why.
Any help would be greatly appreciated. Thanks in advance.
EDIT: ElementStructs is defined as follows:
typedef struct ElementStructs
{
/* Application Specific Definitions */
int index;
char str[100];
} ElementStructs;
The problem resides in this statement:
DataPtr = malloc(sizeof(DataPtr));
You allocate only enough memory to hold a pointer and not a full struct.
You should allocate using:
DatapPtr = malloc(sizeof(ElementStructs));
or, as described in the comments (WhozCraig):
DatapPtr = malloc(sizeof(*DataPtr));
Related
I know the theory of fwrite and fread but I must be making some mistake because I can't make them work. I made a random struct, initialized an array and used fwrite to save it into a binary file. Then I opened the same binary file, used fread and saved what was inside in another array. With the debugger I saw what was inside the second array and it says, for example:
ParkingLot2[0].company= "ffffffffffffffff"
ParkingLot2[0].years=-842150451.
When pasting the code I removed all the stuff that made the code too long like if (f==NULL) for controlling the opening of the file and the pointer==NULL after the mallocs and the control that fread and fwrite read the right amount of data.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Cars {
int years;
char company[16];
}Tcars;
void WriteBinaryFile(char* file_name, Tcars* p_1)
{
FILE* f;
f = fopen(file_name, "wb");
fwrite(p_1, sizeof(Tcars), 3, f);
fclose(f);
return;
}
Tcars* ReadBinaryFile(char* file_name, Tcars* p_2, int* pc)
{
FILE* f;
Tcars temp;
size_t number = 1;
f = fopen("cars.dat", "rb");
while (number) {
number = fread(&temp, sizeof(Tcars), 1, f);
if (number)
(*pc)++;
}
/*i already know that the size is 3 but i want to try this method because in my last exam i
was given a .dat file from my professor and i didn't know how much data i had to read through */
if ((*pc) != 0)
{
p_2 = malloc(sizeof(Tcars) * (*pc));
fread(p_2, sizeof(Tcars), (*pc), f);
}
fclose(f);
return p_2;
}
int main()
{
Tcars* ParkingLot1 = malloc(sizeof(Tcars) * 3);
for(int i=0;i<3;i++)
{
ParkingLot1[i].years = 2000 + i;
}
strcpy(ParkingLot1[0].company, "Fiat");
strcpy(ParkingLot1[1].company, "Ford");
strcpy(ParkingLot1[2].company,"Toyota");
Tcars* ParkingLot2 = NULL;
int cars_amount = 0;
WriteBinaryFile("cars.dat", ParkingLot1);
ParkingLot2 = ReadBinaryFile("cars.dat", ParkingLot2, &cars_amount);
free(ParkingLot1);
free(ParkingLot2);
return 0;
}
You have a number of small (and some not so small errors) that are causing you problems. Your primary problem is passing Tcars* p_2 to ReadBinaryFile() and allocating with p_2 = malloc(sizeof(Tcars) * (*pc)); each time. Why?
Each call to malloc() returns a new block of memory with a new and different address. You overwrite the address of p_2 with each new call, creating a memory leak and losing the data stored prior to the last call. Instead, you need to realloc() to reallocate a larger block of memory and copy your existing data to the new larger block so you can add the next Tcars worth of data at the end of the reallocated block.
If you are reading data from one file, then there is no need to pass p_2 as a parameter to begin with. Simply declare a new pointer in ReadBinaryFile() and realloc() and add each Tcars worth of data at the end and then return the newly allocated pointer. (you must validate every allocation and reallocation)
Your choice of void for WriteBinaryFile() will conceal any error encountered creating or writing to your new file. You must validate EVERY input/output file operation, especially if the data written will be used later in your program. A simple choice of return of type int returning 0 for failure and 1 for success (or vice-versa, up to you) is all you need. That way you can handle any error during file creation or writing and not blindly assume success.
A slightly more subtle issue/error is your allocation for ParkingLot1 using malloc(). Ideally you would use calloc() or use memset to set all bytes zero. Why? You write the entire Tcars struct to the file. malloc() does not initialize the memory allocated. That means all characters in the company name between the end of the name (the nul-terminating character) and the end of the 16 bytes of storage will be uninitialized. While that will not cause problems with your read or write, it is far better to ensure all data being written to your file is initialized data. Otherwise examining the contents of the file will show blocks of uninitialized values written to the file.
Another small style issue is the '*' in the declaration of a pointer generally goes with the variable and not the type. Why?
Tcars* a, b, c;
The declaration above most certainly does not declare 3-pointers of type Tcars, instead it declares pointer a and two struct of type Tcars with automatic storage duration b, and c. Writing:
Tcars *a, b, c;
makes that clear.
Lastly, don't use MagicNumbers or hardcode filenames in your functions. You shouldn't need to recompile your code just to read or write a different filename. It's fine to use "cars.dat" as a default filename in main(), but either take the filenames as the 1st argument to your program (that's what int argc, char **argv parameters to main() are for) or prompt the user for a filename and take it as input. 3 and 16 are MagicNumbers. If you need a constant, #define them or use a global enum.
Putting it altogether, you could do something similar to the following to read an unknown number of Tcars from your data file:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCARS 3 /* if you need a constant, #define one (or more) */
#define COMPANY 16
typedef struct Cars {
int years;
char company[COMPANY];
} Tcars;
/* returns 1 on success 0 on error */
int WriteBinaryFile (char *file_name, Tcars *p_1, size_t nelem)
{
FILE *f;
size_t size = sizeof *p_1;
f = fopen (file_name, "wb");
if (!f) { /* validate file open for writing */
perror ("fopen-file_name-write");
return 0;
}
/* validate that nelem blocks of size are written to file */
if (fwrite (p_1, size, nelem, f) != nelem) {
return 0;
}
if (fclose (f)) { /* validate close-after-write */
perror ("fclose-f");
return 0;
}
return 1;
}
/* returns pointer to allocated block holding ncars cars on success,
* NULL on failure to read any cars from file_name.
*/
Tcars *ReadBinaryFile (char *file_name, size_t *ncars)
{
FILE *f;
Tcars *tcars = NULL, temp;
size_t nelem = *ncars, size = sizeof (Tcars);
f = fopen (file_name, "rb");
if (!f) {
perror ("fopen-file_name-read");
return NULL;
}
while (fread (&temp, size, 1, f) == 1) {
/* always realloc to a temporary pointer */
void *tempptr = realloc (tcars, (nelem + 1) * size);
if (!tempptr) { /* validate realloc succeeds or handle error */
perror ("realloc-tcars");
break;
}
tcars = tempptr; /* assign reallocated block */
memcpy (tcars + nelem, &temp, size); /* copy new car to end of block */
nelem += 1;
}
fclose (f);
*ncars = nelem;
return tcars;
}
/* void is fine for print functions with no bearing on the
* continued operation of your code.
*/
void prn_cars (Tcars *cars, size_t nelem)
{
for (size_t i = 0; i < nelem; i++) {
printf ("%4d %s\n", cars[i].years, cars[i].company);
}
}
int main (int argc, char **argv)
{
/* read from filename provided as 1st argument ("cars.dat" by default) */
char *filename = argc > 1 ? argv[1] : "cars.dat";
/* must use calloc() on ParkingLot1 or zero memory to avoid writing
* unintialized characters (rest of company) to file.
*/
Tcars *ParkingLot1 = calloc (NCARS, sizeof(Tcars)),
*ParkingLot2 = NULL;
size_t cars_amount = 0;
if (!ParkingLot1) { /* validate EVERY allocation */
perror ("calloc-ParkingLot1");
return 1;
}
for (int i = 0; i < NCARS; i++) {
ParkingLot1[i].years = 2000 + i;
}
strcpy (ParkingLot1[0].company, "Fiat");
strcpy (ParkingLot1[1].company, "Ford");
strcpy (ParkingLot1[2].company,"Toyota");
/* validate WriteBinaryFile succeeds or handle error */
if (!WriteBinaryFile (filename, ParkingLot1, NCARS)) {
return 1;
}
ParkingLot2 = ReadBinaryFile (filename, &cars_amount);
if (ParkingLot2) { /* validate ReadBinaryFile succeeds or handle error */
prn_cars (ParkingLot2, cars_amount); /* output cars read from file */
free (ParkingLot2); /* free if ParkingLot2 not NULL */
}
free(ParkingLot1); /* free ParkingLot1 */
}
(note: you always check the return of fclose() after-a-write to catch any file errors and error flushing the data to the file that can't be caught at the time of the fwrite() call)
Also note in the man page for fread and fwrite they can read or write less than the number of byte (or elements) you request. A short-read may or may not represent an error or premature end-of-file and you need to call ferror() and feof() to determine which, if any, occurred. While direct file reads from disk are not as prone to short-reads as network reads and writes, a full implementation would protect against a short-read regardless of where the data is being read from or written to. Further investigation is left to you.
Example Use/Output
$ ./fwrite_fread_cars dat/cars.dat
2000 Fiat
2001 Ford
2002 Toyota
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./fwrite_fread_cars dat/cars.dat
==7237== Memcheck, a memory error detector
==7237== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7237== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==7237== Command: ./fwrite_fread_cars dat/cars.dat
==7237==
2000 Fiat
2001 Ford
2002 Toyota
==7237==
==7237== HEAP SUMMARY:
==7237== in use at exit: 0 bytes in 0 blocks
==7237== total heap usage: 9 allocs, 9 frees, 10,340 bytes allocated
==7237==
==7237== All heap blocks were freed -- no leaks are possible
==7237==
==7237== For lists of detected and suppressed errors, rerun with: -s
==7237== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have any question.
I've been tasked with getting writing a function that uses dynamic memory and will take a string s and pull out every second element of the string, and then return a new string with those elements. So far my code is:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
char* skipping(const char* s)
{
int inc = 0; //new list incrementer
int len = strlen(s);
char* new_s = malloc(len + 1);
for (int i = 0; i < len - 1; i+=2) {
new_s[inc] = s[i];
inc++;
}
return new_s;
}
int main(void)
{
char* s = skipping("0123456789");
printf("%s\n", s);
free(s);
return 0;
}
This works, however when I run it using Valgrind I get told I have an error, which comes from using strlen, but I can't seem to fix it. Any help would be awesome!
Error messages: (in valgrind)
==4596==
==4596== Conditional jump or move depends on uninitialised value(s)
==4596== at 0x4C32D08: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4596== by 0x4EBC9D1: puts (ioputs.c:35)
==4596== by 0x1087B4: main (in /home/ryan/ENCE260/lab6)
==4596==
02468 //this is the expected output
==4596==
==4596== HEAP SUMMARY:
==4596== in use at exit: 0 bytes in 0 blocks
==4596== total heap usage: 2 allocs, 2 frees, 1,035 bytes allocated
==4596==
==4596== All heap blocks were freed -- no leaks are possible
==4596==
==4596== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Why is Valgrind reporting this error?
From the Valgrind online manual on the use of uninitialised or unaddressable values in system calls:
Sources of uninitialised data tend to be:
- Local variables in procedures which have not been initialised.
- The contents of heap blocks (allocated with malloc, new, or a similar function) before you (or a constructor) write something there.
Valgrind will complain if:
the program has written uninitialised junk from the heap block to the standard output.
Since you have used s in printf without null-terminating it, it caused the error.
I wrote a simple code that reads a very large file into memory. (The file is around 480 mega bytes in size). The file contains some comma separated values of 0s and 1s. The code is fairly straight forward. I first get the file size, then allocate enough buffer space, read the file, separate by comma and just put it in the array. The program is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
long no_of_houses = 1048576L; //dimensions of my final table.
int no_of_appliances = 5;
int no_of_sectors = 48;
int* intended_schedule; // this is where the table will be stored.
intended_schedule = (int*) malloc(no_of_houses * no_of_appliances * no_of_sectors * sizeof(int));
FILE* fptr = fopen("./data/houses.csv", "r"); //this file is around 480 mega bytes.
if(fptr == NULL){
perror("housese file");
exit(0);
}
fseek(fptr, 0L, SEEK_END); //find the size of the file before allocating space
long size = ftell(fptr);
rewind(fptr);
char* buffer = (char*) calloc(1, size); //now we know the size, we can allocate space.
fread(buffer, size, 1, fptr);
char* token = strtok(buffer, ",\n"); //it's a comma separated file. So break from comma
long no = 0;
while(token != NULL){
if(no == no_of_houses*no_of_appliances*no_of_sectors)
break; //guard against unexpectedly big data file.
intended_schedule[no] = token[0] - 48;// it's either 0 or 1. So this is good enough
no++;
token = strtok(NULL, ",\n");
}
fclose(fptr);
free(intended_schedule);
free(buffer);
return 0;
}
I used this code as a function of a bigger program and since it gave me errors, I ran this program through valgrind. This is the result I got:
goodman#node2 analyse_code]$ valgrind ./analyse
==39263== Memcheck, a memory error detector
==39263== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==39263== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==39263== Command: ./analyse
==39263==
==39263== Warning: set address range perms: large range [0x51f8040, 0x411f8040) (undefined)
==39263== Warning: set address range perms: large range [0x59e3f040, 0x77e3f040) (defined)
==39263== Warning: set address range perms: large range [0x59e3f040, 0x77e3f040) (defined)
==39263== Invalid read of size 1
==39263== at 0x4EBEDCC: strtok (in /usr/lib64/libc-2.17.so)
==39263== by 0x400997: main (analyse.c:36)
==39263== Address 0x77e3f040 is 0 bytes after a block of size 503,316,480 alloc'd
==39263== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==39263== by 0x400904: main (analyse.c:27)
==39263==
==39263== Invalid read of size 1
==39263== at 0x4EBEDFC: strtok (in /usr/lib64/libc-2.17.so)
==39263== by 0x400997: main (analyse.c:36)
==39263== Address 0x77e3f040 is 0 bytes after a block of size 503,316,480 alloc'd
==39263== at 0x4C2B9B5: calloc (vg_replace_malloc.c:711)
==39263== by 0x400904: main (analyse.c:27)
==39263==
==39263== Warning: set address range perms: large range [0x51f8028, 0x411f8058) (noaccess)
==39263== Warning: set address range perms: large range [0x59e3f028, 0x77e3f058) (noaccess)
==39263==
==39263== HEAP SUMMARY:
==39263== in use at exit: 0 bytes in 0 blocks
==39263== total heap usage: 3 allocs, 3 frees, 1,509,950,008 bytes allocated
==39263==
==39263== All heap blocks were freed -- no leaks are possible
==39263==
==39263== For counts of detected and suppressed errors, rerun with: -v
==39263== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
I'm wondering why I get these errors. As far as I can tell, there are no problems with my code. Is it because my data is too large? I don't think that could be the case since I run this code on a server with 128 GB of RAM.
Any help would be appreciated.
--ppgoodman
strtok() assumes a NUL-terminated string, your buffer is NOT NUL-terminated, so strtok() will try to walk beyond the end of your buffer. But you can do withoutstrtok() and the large buffer.
You don't need to buffer the entire file; for simple cases like this, you can step through it using a one-character buffer. This will consume less memory and will also be consirably faster (at least 2 times)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
unsigned long no_of_houses = 1048576L; //dimensions of my final table.
unsigned int no_of_appliances = 5;
unsigned int no_of_sectors = 48;
unsigned long no = 0;
int ch;
unsigned int *intended_schedule; // this is where the table will be stored.
intended_schedule = malloc(no_of_houses * no_of_appliances * no_of_sectors * sizeof *intended_schedule);
FILE *fptr = fopen("./data/houses.csv", "r"); //this file is around 480 mega bytes.
if(!fptr) {
perror("housese file");
exit(0);
}
while(no < no_of_houses*no_of_appliances*no_of_sectors) {
ch = getc(fptr);
if (ch== EOF) break;
if (ch== '\n') continue;
if (ch== ',') continue;
intended_schedule[no++] = ch - '0'; // it's either 0 or 1. So this is good enough
}
fclose(fptr);
free(intended_schedule);
return 0;
}
I am trying to solve a problem of "Multiplying a number by 11".Number can be any long.I am getting SIGABRT error.
I tried to debug using valgrind, but i don't know to solve it(saw many questions of valgrind on stackoverflow but no success).I am stuck on this problem since last week.
Code is :
#include <stdio.h>
#include <stdlib.h>
#define CHUNK 10
void get_input(char *val,int *i){
char ch,*tmp=NULL;
int size;
size=CHUNK;
while(ch=getc(stdin),ch!=EOF && ch!='\n'){
val[(*i)++]=ch;
if(*i>=size){
size+=CHUNK;
tmp=realloc(val,size);
if(!tmp){
free(val);
val=NULL;
break;
}
val=tmp;
}
}
val[*i]='\0';
}
void mul_11(char *val,int *i){
int *digit,iter,j,carry=0,num,temp;
iter=*i;
digit=(int*)malloc((iter+2)*sizeof(int));
for(j=iter-1;j>=0;j--){
temp=val[j]-'0';
num=temp*11+carry;
digit[j+2]=num%10;
carry=num/10;
}
digit[1]=carry%10;
digit[0]=carry/10;
if(digit[0]==0)
temp=1;
else
temp=0;
for(j=temp;j<=iter+1;j++)
printf("%d",digit[j]);
free(digit);
digit=NULL;
*i=0;
}
int main() {
int t,i=0;
char *val=NULL;
scanf("%d ",&t);
while(t--){
val=(char*)malloc(CHUNK*sizeof(char));
get_input(val,&i);
mul_11(val,&i);
printf("\n");
free(val);
val=NULL;
}
return 0;
}
Whole code with input can be found out Geeksforgeeks code here
Valgrind error :
5555555555555555555555555555555555555
==2349== Invalid read of size 1
==2349== at 0x4008CE: mul_11 (mul11.c:30)
==2349== by 0x400A8A: main (mul11.c:55)
==2349== Address 0x52044a4 is 20 bytes after a block of size 16 in arena "client"
==2349==
6111111105-3-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-6-60-8
==2349== Invalid free() / delete / delete[] / realloc()
==2349== at 0x4C2EDEB: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2349== by 0x400AA0: main (mul11.c:57)
==2349== Address 0x5204480 is 0 bytes inside a block of size 10 free'd
==2349== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2349== by 0x400809: get_input (mul11.c:13)
==2349== by 0x400A77: main (mul11.c:54)
==2349== Block was alloc'd at
==2349== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2349== by 0x400A60: main (mul11.c:53)
==2349==
If get_input reallocs your val and it gets a new address, the caller (main) will not be told that its value for val has become invalid (realloc has freed it). mul_11 will be using freed memory, and main will then free it for the second time.
One solution is to send in a pointer to the address, if the function can realloc it, so the caller gets the new values.
void get_input(char **valp,int *i){
char *val = *valp;
...
val = realloc ...
*valp = val;
...
I get a segmentation fault on the fscanf line below. I added the character width for each variable to try and fix it so I don't understand why it would seg fault.
I read from a CSV file into an array of structs.
The struct is:
typedef struct Person
{
int ID;
int salary;
int deleted;
char salutation[4];
char firstName[21];
char surName[31];
char job[16];
} Person;
I declare the array of structs:
Person* persons;
persons = (Person*)malloc(SIZE * sizeof(Person));
And then use this while loop to read the CSV file into the values:
(i is initialised at 0)
while(fscanf(f, "%d,%3[^,],%20[^,],%30[^,],%15[^,],%d,%d", &inPersons[i].ID, inPersons[i].salutation, inPersons[i].firstName, inPersons[i].surName, inPersons[i].job, &inPersons[i].salary, &inPersons[i].deleted)!=EOF)
{
newID = inPersons[i].ID;
i++;
}
The segfault happens during the fscanf statement. I'm not experienced with valgrind but it gives me this error for that line:
==16810== Invalid write of size 4
==16810== at 0x578215: _IO_vfscanf (in /lib/libc-2.12.so)
==16810== by 0x585368: __isoc99_fscanf (in /lib/libc-2.12.so)
==16810== by 0x8048951: loadDb (Database.c:23)
==16810== by 0x8048711: menu (Menu.c:37)
==16810== by 0x804861E: main (main.c:6)
==16810== Address 0x27230128 is not stack'd, malloc'd or (recently) free'd
I also get these Valgrind faults for the same line:
==18457== Use of uninitialised value of size 4
==18457== at 0x405A215: _IO_vfscanf (in /lib/libc-2.12.so)
==18457== by 0x4067368: __isoc99_fscanf (in /lib/libc-2.12.so)
==18457== by 0x8048943: loadDb (Database.c:23)
==18457== by 0x8048711: menu (Menu.c:37)
==18457== by 0x804861E: main (main.c:6)
==18457== Process terminating with default action of signal 11 (SIGSEGV)
==18457== Access not within mapped region at address 0x5C5E4128
==18457== at 0x405A215: _IO_vfscanf (in /lib/libc-2.12.so)
==18457== by 0x4067368: __isoc99_fscanf (in /lib/libc-2.12.so)
==18457== by 0x8048943: loadDb (Database.c:23)
==18457== by 0x8048711: menu (Menu.c:37)
==18457== by 0x804861E: main (main.c:6)
If you have an alphabetic or punctuation character where you should have a digit, you have an infinite loop and you overflow the bounds of the array of people that you allocated. You should be checking:
while (i < SIZE && (num = fscanf(f, "...", ...)) == 7)
{
...process valid input...
}
...consider what to do here, using `num` to distinguish between EOF and failed conversions...
The fact that valgrind can't identify the memory is puzzling. You've taken most of the relevant steps to ensure that you don't get buffer overflows (all except checking on the status of fscanf() properly).
Oh…you allocate persons; you're reading into inPersons…which is correct?
I think I would be writing a function to call fscanf() and detect and report errors, and then calling that from the while loop:
while (i < SIZE && get_person(&persons[i]) != EOF)
...
or:
while (i < SIZE && get_person(&inPersons[i]) != EOF)
...
This also allows you to switch from fscanf() to either fgets() and sscanf(), or getline() and sscanf().