@kyklaed

Где ошибка в коде, потерялся символ, и не работает free()?

Привет, код программы это обработка входного потока и запись сим волов в массив,
в функции del_spacetab я считаю сколько пробелов до конца строки.

вопрос в том что строки после добавления в массив не выводятся каждая на свою строку. хотя я не удаляю символы перехода на новую строку . и второй вопрос почему в функции coppy - программа крашится на освобождении памяти free(p1) ? не могу понять в чем ошибка. при компилировании нет ошибок. и предупреждений

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

int getlen(char **p1,char **p2);
void pprint(char **p1, int len);
int del_spacetab(char **p1,int len);
void coppy(char **p2,char **p1, int len_p2,int len,int *first_round);

int main(){
	char *p1, *p2;
	int len;
	int len2;
	int len_p2;
	int len_max = 8;
	int first_round =0;
	p1 = (char*)malloc(1000 * sizeof(char));
	p2 = (char*)malloc(1000 * sizeof(char));
	len_p2=0;
	while ((len = getlen(&p1,&p2)) >0){
		if (len >= len_max){
			len2 = del_spacetab(&p1,len);
			len-=len2;
			len_p2 += len;
			coppy(&p2, &p1,len_p2,len,&first_round);
			
		}
	}
	printf("Total:\n");
	int i;
	for (i=0;i<len_p2;++i){
		printf("%c",p2[i]);
	}
	free(p2);
	return 0;
}

int getlen(char **p1,char **p2){
	int c, i;
	for (i=0;  (c=getchar()) != EOF && c != '\n'; ++i){
		if (i==1000){
			(*p1) = (char*)realloc(*p1, 100000 * sizeof(char));
			(*p2) = (char*)realloc(*p2, 100000 * sizeof(char));	
		}
		(*p1)[i]=c;
	}
	if (c == '\n'){
		(*p1)[i]=c;
		++i;
	}
	(*p1)[i]='\0';
	return i;
}

void pprint(char **p1, int len){
	int i;
	for (i=0;  i<len; ++i){
		printf("%c",(*p1)[i]);
	}
}

int del_spacetab(char **p1,int len){
	int i;
	int n=0;
	for (i=0;i<len;i++){
		if ((*p1)[i] == ' ' || (*p1)[i] == '\t' && (*p1)[i] != '\n'){
			n++;
		}
		else if ((*p1)[i] != '\n'){
			n=0;
		}

		if ((*p1)[i] == '\n'){
			//n++;
			
			return n;	
		}
	}
}

void coppy(char **p2,char **p1,int len_p2,int len,int *first_round){
	int i,n;
	n=0;
	if (*first_round == 0) { 
		*first_round=1;
		i =0;
		len=0;
		
	} 
	else {
		i=len_p2-len;
	}
	for (; i< len_p2; ++i){
		(*p2)[i] = (*p1)[n]; 
		n++;
	}
	free(*p1);
}
  • Вопрос задан
  • 202 просмотра
Решения вопроса 2
myjcom
@myjcom
*** Error in `/home/a.out': double free or corruption (!prev): 0x0000000000d95010 ***

while ((len = getlen(&p1,&p2)) >0){
    if (len >= len_max){
      len2 = del_spacetab(&p1,len);
      len-=len2;
      len_p2 += len;

      coppy(&p2, &p1,len_p2,len,&first_round);

    }

при втором вызове coppy(&p2, &p1,len_p2,len,&first_round);
Вы повторно вызываете free() для одного и того же указателя.
В стандарте Си это Undefined behavior.
Ответ написан
@res2001
Developer, ex-admin
Крашится на free скорее всего из-за того, что у вас где-то выход за границу массива и вы перезаписываете служебные данные менеджера памяти. Нужно искать выходы за границу массива.

1.Как минимум ошибка при realloc - вы увеличиваете массив только 1 раз, а что если строка попадется очень длинная и нужно будет еще увеличивать буфер?
Вам нужно в getlen передавать текущий размер буферов и возвращать из нее новый размер, если был realloc.
Кроме того нужно определить до какого максимального предела вы готовы увеличивать буфера - память не безграничная (даже виртуальная) и если буфера вырастают за допустимый предел - нужно выдать ошибку и завершить программу.

2. В del_spacetab лишние условия в if:
if ((*p1)[i] == ' ' || (*p1)[i] == '\t' && (*p1)[i] != '\n')
Если я все правильно понимаю, то не равенство с '\n' тут излишне, или может быть не хватает скобок. Обычно, если в логическом выражении нужно использовать и || и &&, то для большей читаемости нужно использовать скобки для точного определения того что вы хотите сказать этим выражением.
Следующим else if - вы обнуляете счетчик на каждом не пробельном символе ...
Ну и функция del_spacetab не делает то что вы хотите - она просто возвращает количество "пробельных" символов, потом вы при копировании их не отбрасываете.

3.В функциях, кроме getline, не нужно передавать двойные указатели на буфера - достаточно простых указателей.
В getline нужны двойные указатели потому что в случае увеличения размера буфера вы должны через них вернуть указатели на новые буфера. В остальных функциях это не требуется.

PS: Запустите программу под отладчиком и отслеживайте все изменения состояния (переменных) в ручную.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы
23 нояб. 2024, в 22:03
3000 руб./за проект
23 нояб. 2024, в 21:53
30000 руб./за проект
23 нояб. 2024, в 21:49
1000 руб./в час