Invalid read and write of size 8 happening in modify_tab_size().
what am I doing wrong? Ive tried almost everything, I dont understand it.
Invalid read of size 8
==131939== at 0x10ADC9: modify_tab_size (in /home/jgten/test)
...
2 errors in context 2 of 2:
==131939== Invalid write of size 8
==131939== at 0x10ADEA: modify_tab_size (in /home/jgten/test)
// Cunit test
void test_erase_repeat_0(void) {
int val = 3;
int *val1 = &val;
FILE *file = fopen("temp.txt", "w ");
fprintf(file, "MATT MATT MIMMIE");
rewind(file);
char **words = calloc(3, sizeof(char *));
place_words_in_array(file, words);
CU_ASSERT_EQUAL(erase_repeated(val1,words), 2);
for (int i = 0; i < 2; i)
free(words[i]);
free(words);
fclose(file);
}
// Function being tested.
int erase_repeated(int *nb_words, char **words) {
for (int i = 0; i < *nb_words; i) {
if (words[i] != 0) {
for (int b = 0; b < *nb_words; b) {
if (strcmp(words[i], words[b]) == 0 && b != i)
modify_tab_size(&b, nb_words, words);
}
}
}
return *nb_mots;
}
void modify_tab_size(int *b, int *nb_words_update, char **words) {
free(words[*b]);
for (int k = *b; k < *nb_words_update; k ) {
words[k] = words[k 1]; <--------------------------read error
words[*nb_words_update 1] = 0; <--------------------------write error
}
(*nb_words_update)--;
(*b)--;
}
int place_words_in_array(FILE *file, char **words) {
int position = 0;
char line[80];
while (fgets(line, 80, file)) {
char *word = strtok(line, " ,.-\n");
while (word != NULL) {
words[position ] = strdup(word);
word = strtok(NULL, " ,.-\n");
}
}
return position != 0;
}
CodePudding user response:
The problem is k 1
and *nb_words_update 1
can walk off the array, and it is. Add printf("k:%d, k 1:%d, *nb_words_update 1: %d\n", k, k 1, *nb_words_update 1);
into the loop to see.
k:1, k 1:2, *nb_words_update 1: 4
k:2, k 1:3, *nb_words_update 1: 4
You've only allocated three slots, 3 and 4 walk off the end of the array.
Since nb_words_update
starts as the length of the array, words[*nb_words_update 1] = 0;
is always going to be too large. words[*nb_words_update] = 0;
is also too large.
What you seem to be trying to do is deleting an element from an array by shifting everything after it to the left.
void delete_element(char **words, int *b, int *size) {
// Free the string to be deleted.
free(words[*b]);
// Only go up to the second to last element to avoid walking off the array.
for (int i = *b; i < *size-1; i ) {
// Shift everything to the left.
words[i] = words[i 1];
}
// Null out the last element.
// Don't use 0 for NULL, it's confusing.
words[*size-1] = NULL;
// Decrement the size of the array.
(*size)--;
// Redo the check with the newly shifted element.
(*b)--;
}
This sort of thing is better done with a linked list.
Note that your code has a bug. The result is an array of two elements, but one of them is blank. In addition to the return value of erase_repeated
, also test its side effect which is to modify words
. Test that words
contains what you think it does.