I'm writing a program that loads input until a specific word is typed in,in this case its word "konec".Although my program seems to work just about ok,I can't solve this Valgrind error
==16573== Memcheck, a memory error detector
==16573== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==16573== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==16573== Command: ./s_main_o
==16573==
==16573== Conditional jump or move depends on uninitialised value(s)
==16573== at 0x4C2A020: strcmp (mc_replace_strmem.c:711)
==16573== by 0x4008D7: main (main.c:41)
==16573== Uninitialised value was created by a heap allocation
==16573== at 0x4C28CCE: realloc (vg_replace_malloc.c:632)
==16573== by 0x40089C: main (main.c:38)
==16573==
==16573== Conditional jump or move depends on uninitialised value(s)
==16573== at 0x4C2A024: strcmp (mc_replace_strmem.c:711)
==16573== by 0x4008D7: main (main.c:41)
==16573== Uninitialised value was created by a heap allocation
==16573== at 0x4C28CCE: realloc (vg_replace_malloc.c:632)
==16573== by 0x40089C: main (main.c:38)
==16573==
==16573==
==16573== HEAP SUMMARY:
==16573== in use at exit: 0 bytes in 0 blocks
==16573== total heap usage: 8 allocs, 8 frees, 1,125 bytes allocated
==16573==
==16573== All heap blocks were freed -- no leaks are possible
==16573==
==16573== For counts of detected and suppressed errors, rerun with: -v
==16573== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)
And here part of the used code
int main() {
int numberOfWords, i;
char** words;
char* word;
int* rarity;
char* konec = "konec";
int amount = 0;
double percentage;
words = malloc(10 * sizeof (char*));
rarity = calloc(256, sizeof (int));
numberOfWords = 0;
words[0] = 0;
int working = 1;
while (working == 1) {
int length = 0;
word = calloc((length + 1),sizeof (char));
char c;
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\n') {
break;
}
length++;
word = realloc(word, length + 1);
word[length - 1] = c;
}
if (strcmp(word, konec) == 0) {
working = 0;
free(word);
break;
}
}
}
I have found lots of topics discussing the same problem,but I wasn't able to find solution anyway.Thanks for your answers.
The problem is that you do not add a null terminator on reallocation:
word = realloc(word, length + 1);
word[length - 1] = c;
At this point, word string is not terminated, so strcmp may go off its end in search of null terminator. For example, when you type "ko", strcmp will determine that characters 0 and 1 are the same, and try checking word[2] - a location that your program did not set.
Add this line to fix the problem:
word[length] = '\0';
You should also add code to free word when comparison to konec is unsuccessful.
Note: You are not using realloc correctly: instead of assigning it back to word, you should assign it to temp, and check it for NULL. Otherwise, you would have no way of freeing previously allocated word when realloc fails.
Related
So i have this uni assignment for which i have to count votes coming from the input and sort them by the max amount(alphabetical if the number is equal). The uni server is running tests on it, putting different names/numbers in there, and i got some points already, but I'm having an issue with a certain input. This is the error I'm getting:
==30190== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==30190== Using Valgrind-3.14.0 and LibVEX; rerun with -h for copyright info
==30190== Command: ./run
==30190==
==30190== Invalid write of size 1
==30190== at 0x1092AA: main (program.c:23)
==30190== Address 0x1fff001000 is not stack'd, malloc'd or (recently) free'd
==30190==
==30190==
==30190== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==30190== Access not within mapped region at address 0x1FFF001000
==30190== at 0x1092AA: main (program.c:23)
==30190== If you believe this happened as a result of a stack
==30190== overflow in your program's main thread (unlikely but
==30190== possible), you can try to increase the size of the
==30190== main thread stack using the --main-stacksize= flag.
==30190== The main thread stack size used in this run was 8388608.
==30190==
==30190== HEAP SUMMARY:
==30190== in use at exit: 0 bytes in 0 blocks
==30190== total heap usage: 1 allocs, 1 frees, 4,096 bytes allocated
==30190==
==30190== All heap blocks were freed -- no leaks are possible
==30190==
==30190== For counts of detected and suppressed errors, rerun with: -v
==30190== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
//Declaration
char s[20][50],st[50],sabc[20][50];
int i,j,k,l,num[20],e[20][20],suc[20],end[20],ooo;
for(i=0;i<20;i++){
memset(s[i],'\0',50);
suc[i]=0;
for(j=0;j<20;j++){
e[i][j]=-1;
}
}
//Reading the input and putting it into the s array
gets(st);
i=0;
while(st[0]!='\0'){
for(j=0;j<=strlen(st);j++){
s[i][j]=st[j];
}
gets(st);
i++;
}
//The the individual strings are converted into just numbers and put into the num array
for(i=0;i<20;i++){
num[i]=atoi(s[i]);
}
//The opposite, converting the strings into just characters, so only the names are left into the sabc array
for(i=0;i<20;i++){
k=0;
for(j=0;j<50;j++){
if(s[i][j]<48 || s[i][j]>57){
sabc[i][k]=s[i][j];
k++;
}
}
}
//The e array, is here for letting me know at which positions are the strings with the same names.
for(i=0;i<20;i++){
for(j=0;j<20;j++){
l=0;
for(k=4;k<10;k++){
if(s[i][k]==s[j][k]){
l++;
}
}
if(l>5){
e[i][j]=j;
}
}
}
//Here I'm using the previously created e array to count the number of votes together, the suc array is the number of votes counted together
for(i=0;i<20;i++){
for(j=0;j<20;j++){
if(e[i][j]>=0){
suc[i]=suc[i]+num[j];
}
}
}
//Now the previous loop created duplicates, so im using this loop to remove them
for(i=0;i<20;i++){
if(sabc[i][0]=='\0')
continue;
for(j=0;j<20;j++){
if(i==j)
continue;
l=0;
for(k=4;k<10;k++){
if(sabc[i][k]==sabc[j][k]){
l++;
}
}
if(l>5){
memset(sabc[j],'\0',50);
if(suc[i]<suc[j])
suc[i]=suc[j];
}
}
end[i]=suc[i];
}
//And this is the last part, sorting them by number of votes, and alphabeticaly if necessary
memset(st,'\0',50);
for(i=0;i<20;i++){
for(j=0;j<20;j++){
if(end[j]=='\0')
break;
if(end[j]<end[j+1]){
for(k=0;k<50;k++){
st[k]=sabc[j][k];
sabc[j][k]=sabc[j+1][k];
sabc[j+1][k]=st[k];
}
ooo=end[j];
end[j]=end[j+1];
end[j+1]=ooo;
}
if(end[j]==end[j+1]){
if(strcmp(sabc[j],sabc[j+1])>0){
for(k=0;k<50;k++){
st[k]=sabc[j][k];
sabc[j][k]=sabc[j+1][k];
sabc[j+1][k]=st[k];
}
}
}
}
}
//Writing the output
printf("Vysledky:\n");
for(i=0;i<20;i++){
if(sabc[i][0]=='\0')
continue;
printf("%d",end[i]);
puts(sabc[i]);
}
return 0;
}
I know its probably not really optimized, but its what i came up with.
This part of the code just reads the string and puts it into a 2d array.
Also I'm using a program called Putty connected to the uni's server, and it works fine in there, but for some reason it doesn't work on the uni site.
The input I'm having trouble with is:
4 Myne Lajad
5 Draxton Vorgthar
4 Needira Thontwi
4 Oyaka Wrathpry
5 Thrad Zex'lek
Expected output:
5 Draxton Vorgthar
5 Thrad Zex'lek
4 Myne Lajad
4 Needira Thontwi
4 Oyaka Wrathpry
The input can also contain the same names multiple times, but i have that covered. I can also provide the whole code if necessary.
Hello I wrote this function in C that takes a string of words and returns a two dimensional char array with each case initialized to a word in the right order, I compiled and it did the assigned task
char **decompose_string(char *string)
{
int i,j=0;
char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*)); //string_words_number return the number of words in string string
for(i=0;i<string_words_number(string);i++)
{
temp=NULL;
int l=0;
while(string[j]!=' ' && *string)
{
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]=string[j];
j++;l++;
}
j++;
temp[l]='\0';
tab_mots=realloc(words_array,(string_words_number(string)+1)*sizeof(char)*(j-1));
words_array[i]=temp;
}
words_array[i]=NULL;
return words_array;}
And my main:
int main()
{
char* string1= "word1 and word2 and word3";
printf("Our initial string: %s\n",string1);
char** words_array1;
printf("After decomposition:\n");
words_array1=decompose_string(string1);
display_words_array(words_array1); //displays each element of the array in a line
words_array1=destroy_array(words_array1);
return 0;}
But as I executed the valgrind command to see weither there are any memory leaks this was the result:
==4648== Memcheck, a memory error detector
==4648== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4648== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4648== Command: ./test_csvl
==4648==
Our initial array: word1 and word2 and word3
After decomposition:
==4648== Invalid write of size 1
==4648== at 0x4009D9: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==
==4648== Invalid read of size 1
==4648== at 0x4C30F74: strlen (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x4EA969B: puts (ioputs.c:35)
==4648== by 0x400888: display_words_array (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40079F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648== Address 0x5204634 is 0 bytes after a block of size 4 alloc'd
==4648== at 0x4C2FD5F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4648== by 0x40097D: decompose_string (in /home/omaima/2I001/TME3/test_csvl)
==4648== by 0x40078F: main (in /home/omaima/2I001/TME3/test_csvl)
==4648==
word1
and
word2
and
word3
==4648==
==4648== HEAP SUMMARY:
==4648== in use at exit: 8 bytes in 1 blocks
==4648== total heap usage: 30 allocs, 29 frees, 1,545 bytes allocated
==4648==
==4648== LEAK SUMMARY:
==4648== definitely lost: 8 bytes in 1 blocks
==4648== indirectly lost: 0 bytes in 0 blocks
==4648== possibly lost: 0 bytes in 0 blocks
==4648== still reachable: 0 bytes in 0 blocks
==4648== suppressed: 0 bytes in 0 blocks
==4648== Rerun with --leak-check=full to see details of leaked memory
==4648==
==4648== For counts of detected and suppressed errors, rerun with: -v
==4648== ERROR SUMMARY: 9 errors from 2 contexts (suppressed: 0 from 0)
I know that the missing free is the one for temp in the function but if I do free it I'll end up losing its value which I need for my array. So my question would be can I free it without losing its value ? or any other solution to guarantee both the functionality of my function and the erase of any memory leaks. Thank you for your time.
Sorry I forgot here's the function I used to free the allocated space:
char **destroy_words_array( char** words_array)
{
int i;
for(i=0;i<count_words(words_array);i++) free(words_array[i]); //wount_words return the number of elements of the array
free(words_array);
return words_array;
}
The memory leak isn't where you think it is. It happens at the start of your function:
char* temp=malloc(sizeof(char*));
char **words_array=malloc((string_words_number(string)+1)*sizeof(char*));
for(i=0;i<string_words_number(string);i++)
{
temp=NULL;
You allocate space for a pointer to temp, but then you overwrite that pointer when you enter the for loop. Remove that malloc call and the leak goes away.
You have a bigger problem however, and that is reading and writing past the end of an allocated buffer. That's happening here:
temp=NULL;
int l=0;
while(string[j]!=' ' && *string)
{
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]=string[j];
j++;l++;
}
j++;
temp[l]='\0';
Suppose the string in question has two characters to read. On the first iteration of your loop, l is 0, so you allocate l+1 == 1 bytes to temp. You then write to temp[l] == temp[0], which is fine, then you increment l to 1. On the next iteration, you allocate l+1 == 2 bytes for temp, write to temp[l] == temp[1], and increment l to 2. Still good so far.
The problem is when you do temp[l]='\0'; outside of the loop. l is now 2, and the size of the allocated memory is 2, so you're writing one element past the end of the array.
You need to allocate one more byte here:
j++;
temp=realloc(temp,(l+1)*sizeof(char));
temp[l]='\0';
Note also that you should be checking the return value of malloc and realloc throughout your code in case it fails.
Also, you're not correctly checking for the end of string. You need to do:
while(string[j]!=' ' && string[j]!=0)
Before the for-loop you have
char* temp=malloc(sizeof(char*));
but the first thing inside the for-loop is
temp=NULL;
So the memory that temp pointed to is lost. If you run this program on a 64 bit computer, you will see a memory leak of size 8. Remove the first declaration of temp and change the first line in the for-loop to
char* temp = NULL;
Another problem is the condition of the inner while-loop:
while(chaine[j]!=' ' && *chaine)
as you don't advance the chaine pointer, the value of *chaine will not change. You probably meant to write chaine[j] here:
while(chaine[j]!=' ' && chaine[j])
which is equivalent to
while(chaine[j]!=' ' && chaine[j]!='\0')
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 have a program that is supposed to receive input, remember the longest string and print it out at EOF. My code works, but when run through a debugger there is a memory leak detected. I am compiling in Windows and do not have a proper debugger like Valgrind so I do not get much information about the error. The only thing I can imagine can cause this leak is the realloc() or free() function. However, I am not skilled enough in C to understand what the problem is.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p;
char *line;
int sc;
p = (char*) malloc ( sizeof(char) );
line = (char*) malloc ( sizeof(char) );
int count = 0;
int max = 0;
p[count] = 0;
while ( ( sc = getchar()) != EOF ) {
if ( p == NULL ) {
p = (char*) realloc ( p, sizeof(char) );
}
if ( isalpha(sc) ) {
p[count] = sc;
count++;
p = (char*) realloc( p, (count+1)*sizeof(char) );
p[count] = 0;
} else if ( sc == '\n' || sc == ' ' ) {
if ( count > max ) {
line = (char*) realloc( line, (count+1)*sizeof(char) );
strcpy( line, p );
max = count;
} else if ( count == 0) {
printf("%d characters in longest word: %s\n", max, line);
free(line);
free(p);
break;
}
count = 0;
}
}
return 0;
}
You state in the comments that you "have tried moving both free() to the end of the program", but I don't believe you. The problem appears to be that this is a badly designed program which does not always reach the free() statements because when sc is a space or newline, count is unlikely to be 0, and after count is reset to 0, the next character is read into sc (unlikely to be a space or newline).
Simply moving the calls to free() to the end of the program fixes the memory leak, which was reported by Valgrind:
λ> valgrind --tool=memcheck ./a.out
==2967== Memcheck, a memory error detector
==2967== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==2967== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==2967== Command: ./a.out
==2967==
this is a test
==2967==
==2967== HEAP SUMMARY:
==2967== in use at exit: 10 bytes in 2 blocks
==2967== total heap usage: 14 allocs, 12 frees, 42 bytes allocated
==2967==
==2967== LEAK SUMMARY:
==2967== definitely lost: 10 bytes in 2 blocks
==2967== indirectly lost: 0 bytes in 0 blocks
==2967== possibly lost: 0 bytes in 0 blocks
==2967== still reachable: 0 bytes in 0 blocks
==2967== suppressed: 0 bytes in 0 blocks
==2967== Rerun with --leak-check=full to see details of leaked memory
==2967==
==2967== For counts of detected and suppressed errors, rerun with: -v
==2967== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
But there are many other issues with the code. First, never store the result of a call to realloc() in the only copy of a pointer you have to the memory being reallocated; a null pointer may be returned, and if so you then have a memory leak and lost data. Instead, use a temporary variable to hold the result, and assign this value to the original pointer only after checking for a null pointer. If a null pointer has been returned, the simplest solution is probably to terminate the program with an error message, as is done below; the error could be handled in other ways, so long as it is handled.
The posted code is more complex than it needs to be, with multiple calls to malloc() and realloc(). Instead, initialize p and line to NULL, and reallocate only as needed. There is no need to begin by allocating space for 1 char; this can be done when the first character needs to be stored. Also, there is no need to cast the result of malloc() in C (a different story in C++); and, sizeof char is always 1, so this is redundant and only clutters the code.
The fundamental problem in the posted code seems to be that when a character is read, count is incremented. Then if this character is a space or a newline, count may not be 0, so the exit with deallocation condition may not be met. Instead of complicated conditions, rethink the flow of the program.
After reading a character (unless EOF is encountered), if that character is alphabetic, count should be incremented, and p should be reallocated. If this step is successful, the character should be stored in p[], which should then be null-terminated.
Otherwise, if the character is a \n or a space, max should be compared with count. If count is larger, then line should be reallocated. If this step is successful, the string pointed to by p should be copied to line[]. Then max is given the value of count, and count is reset to 0.
After the loop has terminated, the results are printed only if there were words in the input. Then deallocation can occur before the program terminates.
The isalpha() function and similar functions from ctype.h expect an int value in the range of an unsigned char (or EOF). Often you need to cast the value of arguments to these functions to unsigned char to avoid undefined behavior. But, in this case the cast is unnecessary since getchar() returns an int value in the range of an unsigned char (or EOF).
You might also consider using the isspace() function instead of sc == '\n' || sc == ' '. This would allow other whitespace characters, such as '\t', to separate words in the input. As written in the OP, an input of "one\tword" (where '\t' is a tab character) would result in an output of:
7 characters in longest word: oneword
Here is a modified version of the posted code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p = NULL;
char *line = NULL;
int sc;
int count = 0;
int max = 0;
while ((sc = getchar()) != EOF) {
if (isalpha(sc)) {
++count; // read a letter
char *temp = realloc(p, count + 1); // +1 for '\0'
if (temp == NULL) { // check allocation
perror("Failure to reallocate p");
exit(EXIT_FAILURE);
}
p = temp; // OK to reassign p
p[count-1] = sc; // store character
p[count] = 0; // add null-terminator
} else if (isspace(sc)) {
if (count > max) {
char *temp = realloc(line, count + 1); // +1 for '\0'
if (temp == NULL) { // check allocation
perror("Failure to reallocate line");
exit(EXIT_FAILURE);
}
line = temp; // OK to reassign line
strcpy(line, p);
max = count;
}
count = 0;
}
}
if (max > 0) {
printf("%d characters in longest word: %s\n", max, line);
} else {
puts("No words in input");
}
free(line);
free(p);
return 0;
}
And here is a clean bill of health from Valgrind:
λ> valgrind --tool=memcheck ./a.out
==4753== Memcheck, a memory error detector
==4753== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4753== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==4753== Command: ./a.out
==4753==
this is a testrun
7 characters in longest word: testrun
==4753==
==4753== HEAP SUMMARY:
==4753== in use at exit: 0 bytes in 0 blocks
==4753== total heap usage: 16 allocs, 16 frees, 69 bytes allocated
==4753==
==4753== All heap blocks were freed -- no leaks are possible
==4753==
==4753== For counts of detected and suppressed errors, rerun with: -v
==4753== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I think during debugging after the free() function call; you checked the value of the pointer p and line, and you still see the value(string) it is pointing to. If so that is not memory leak because free() does not change the value of pointer or assign 0 or '\0' character in it. free() just free the block of memory so that next time when you call any memory allocation function it will get that memory as available memory, and allocate it. Therefore after calling free(), we always assign NULL to the pointer like p = NULL;.
Correct the code as below and try:-
free(line);
free(p);
line = NULL;
p = NULL;
break;
Based on your coding approach I'll use calloc (you need) instead of malloc to get rid of that:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char *p = NULL;
char *line = NULL;
int sc;
p = calloc ( sizeof(char), 1);
line = calloc ( sizeof(char),1 );
size_t count = 0;
size_t max = 0;
p[count] = 0;
while ( ( sc = getchar()) != EOF ) {
if ( p == NULL ) {
p = realloc ( p, sizeof(char) );
}
if ( isalpha(sc) ) {
p[count] = (char)sc;
count++;
p = realloc( p, (count+1) * sizeof(char) );
p[count] = 0;
} else if ( sc == '\n' || sc == ' ' ) {
if ( count > max ) {
line = realloc( line, (count+1)*sizeof(char) );
strcpy( line, p );
max = count;
} else if ( count == 0) {
printf("%zu characters in longest word: %s\n", max, line);
free(line);
free(p);
break;
}
count = 0;
}
}
return 0;
}
Output with Valgrind:
==4362== Memcheck, a memory error detector
==4362== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==4362== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==4362== Command: ./program
==4362==
Hello World
5 characters in longest word: Hello
==4362==
==4362== HEAP SUMMARY:
==4362== in use at exit: 0 bytes in 0 blocks
==4362== total heap usage: 15 allocs, 15 frees, 2,096 bytes allocated
==4362==
==4362== All heap blocks were freed -- no leaks are possible
==4362==
==4362== For counts of detected and suppressed errors, rerun with: -v
==4362== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Now try to understand, why is not working with malloc and why is working with calloc.
EDIT
Are you sure that is all about a leak? and is not about an uninitialised value?
I'm saying because if you type a letter works fine, the problem comes with Numbers, hence the calloc sugestion.
This is the Output of Valgrind using your code with no modification:
==5042== Memcheck, a memory error detector
==5042== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==5042== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==5042== Command: ./program
==5042==
1
==5042== Conditional jump or move depends on uninitialised value(s)
==5042== at 0x4E88CC0: vfprintf (vfprintf.c:1632)
==5042== by 0x4E8F898: printf (printf.c:33)
==5042== by 0x40082B: main (in /home/michael/program)
==5042== Uninitialised value was created by a heap allocation
==5042== at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5042== by 0x400715: main (in /home/michael/program)
==5042==
0 characters in longest word:
==5042==
==5042== HEAP SUMMARY:
==5042== in use at exit: 0 bytes in 0 blocks
==5042== total heap usage: 4 allocs, 4 frees, 2,050 bytes allocated
==5042==
==5042== All heap blocks were freed -- no leaks are possible
==5042==
==5042== For counts of detected and suppressed errors, rerun with: -v
==5042== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
So sort of new to C and I am trying to make a listener so that User has to press enter twice to completed typing there input. Then split by the new line and run all the data through a loop and send them through my functions.
I am not sure what i am doing wrong but when the loop right under "//segfaulting at loop" in the code is commented out it runs fine but when I uncomment it and have my call to "// assemble(ftemp);" commented it out it is segfaulting so i know it here just dont know what. Valgrind says the below if that helps at all.
Thanks In Advanced Pete.
==14639== Invalid read of size 1
==14639== at 0x4E7754C: ____strtod_l_internal (strtod_l.c:608)
==14639== by 0x4011F8: main (in /home)
==14639== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==14639== Process terminating with default action of signal 11 (SIGSEGV)
==14639== Access not within mapped region at address 0x0
==14639== at 0x4E7754C: ____strtod_l_internal (strtod_l.c:608)
==14639== by 0x4011F8: main (in /home)
==14639== If you believe this happened as a result of a stack
==14639== overflow in your program's main thread (unlikely but
==14639== possible), you can try to increase the size of the
==14639== main thread stack using the --main-stacksize= flag.
==14639== The main thread stack size used in this run was 8388608.
==14639== HEAP SUMMARY:
==14639== in use at exit: 0 bytes in 0 blocks
==14639== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==14639== All heap blocks were freed -- no leaks are possible
==14639== For counts of detected and suppressed errors, rerun with: -v
==14639== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
My code:
int main(int argc, char * argv[]) {
printf("Please Enter In Float (Hit Enter Twice To Exicute)\n" );
#define MAXLENGTH 1000
char Input_string[MAXLENGTH];
int ilop = 0;
for(;;++ilop)
{
Input_string[ilop] = getchar();
if (ilop > 0 && Input_string[ilop] == '\n' &&
Input_string[ilop-1] == '\n') break;
}
Input_string[ilop] = 0;
char *pch;
// printf ("Splitting string \"%s\" into tokens:\n",Input_string);
pch = strtok (Input_string,"\n");
float ftemp = atof(pch);
//printf("price:, %f\n\n",ftemp);
assemble(ftemp);
//segfaulting at loop
while (pch != NULL)
{
pch = strtok (NULL, "\n");
ftemp = atof(pch);
printf("price:, %f\n\n",ftemp);
// assemble(ftemp);
}
return 0;
}
To expand on what Igal S. said, you’re first setting strtok inside the loop, then using it, and not checking it until the top of the loop. So, on the last iteration, it will set pch to NULL, then pass it to atof() without checking it.
You need something like (untested):
pch = strtok (Input_string, "\n");
while (pch != NULL)
{
/* ... */
pch = strtok (NULL, "\n");
}
There is a possibility of array out of bound access which might lead to undefined behavior.
In the for loop at the beginning add the check
if(ilop > 999)
{
break;
}