C - Получение неверных символов после чтения файла и печати в файл, -maybe- Переполнение буфера
У меня есть файл с именами, фамилиями, идентификаторами и адресами электронной почты, который находится в случайном порядке. Я должен организовать эти данные, записать в структуры и в выходной файл, как организовано. Может быть более одного имени и фамилии. Вот пример disordered.txt:
abc@gmail.com Andee Kenny SMITH 1234
ADAM ADAM abc@gmail.com Andeee 21654
Anderea abc@gmail.com SAMMY 3524654
abc@gmail.com Andi BROWN 1245
Andie abc@gmail.com KNOWY 2485
Andra abc@gmail.com BRUCE 52445
Andrea abc@gmail.com 246574 DENNIS
2154 Andreana abc@gmail.com CHASE
Andree 21524 SIERRRA abc@gmail.com
Andrei 154 MONDY abc@gmail.com
4564765 Andria LE BARC abc@gmail.com
78 Andriana abc@gmail.com WALLS
Мой код отлично работает с этими 12 людьми, но если я много копирую и добавляю новых или добавляю новых людей, то после 33 человек он печатает недопустимые символы перед именами и фамилиями с повторением.
Вот скриншот: организованный.txt
Я предпочел использовать в своей структуре указатели на символы.
Вот мой код:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define WORD_SIZE 30
#define NAME 1
#define SURNAME 2
#define EMAIL 3
#define ID 4
typedef struct ppl {
char* name;
char* surname;
char* eMail;
int id;
} PEOPLE;
int whichDataType (char* buffer);
void writeData (PEOPLE* person, char* buffer, int whichData, int* nameTimes, int* surnameTimes, int personNumber);
void printData (PEOPLE* person, FILE* sptr, int personNumber);
int main (void) {
FILE* fptr = NULL;
fptr = fopen("disorganized.txt", "r");
if (fptr == NULL) {
printf ("Disorganized file couldn't open\n");
printf ("Exiting the program\n");
exit(TRUE);
}
FILE* sptr = NULL;
sptr = fopen("organized.txt", "w");
if (sptr == NULL) {
printf ("Organized file couldn't open\n");
printf ("Exiting the program\n");
exit(TRUE);
}
int whichData;
int personNumber = 0;
int* nameTimes;
int* surnameTimes;
int forOnce = 0;
char* buffer;
int* buffer2;
PEOPLE* person;
person = (PEOPLE*) malloc (sizeof(PEOPLE));
buffer = (char*) malloc ( WORD_SIZE * sizeof(char));
nameTimes = (int*) malloc ( sizeof(int));
surnameTimes = (int*) malloc (sizeof(int));
*nameTimes = 0;
*surnameTimes = 0;
//gets word 'till EOF
while ((fscanf(fptr, "%s", buffer)) == 1) {
if (personNumber != 0) {
//creates new structure
person = (PEOPLE*) realloc (person, personNumber * sizeof(PEOPLE));
}
//looks what type of data
whichData = whichDataType(buffer);
//allocates inside of structures and writes
writeData(person, buffer, whichData, nameTimes, surnameTimes, personNumber);
buffer2 = (int*) malloc (sizeof(int));
*buffer2 = fgetc(fptr); //checks what's coming next
if (*buffer2 == '\n') {
if (forOnce == 0) {
//to open a place for next person in my structure pointer, since personNumber = 0; increasing it with 1 and reallocating it with 1*sizeof(PEOPLE) would be the allocating memory for person 1 twice.
personNumber = personNumber + 2;
free(buffer2);
free(buffer);
buffer = (char*) malloc ( WORD_SIZE * sizeof(char));
*nameTimes = 0;
*surnameTimes = 0;
++forOnce;
}
else {
++personNumber;
free(buffer2);
free(buffer);
buffer = (char*) malloc ( WORD_SIZE * sizeof(char));
*nameTimes = 0;
*surnameTimes = 0;
}
}
else if (*buffer2 == ' ' || *buffer2 == '\t') {
free(buffer2);
free(buffer);
buffer = (char*) malloc ( WORD_SIZE * sizeof(char));
}
}
--personNumber; //my algorithm increases it 1 more time which is redundant
printData (person, sptr, personNumber);
int i;
for (i = 0; i<personNumber; ++i) {
free((person+i)->name);
free((person+i)->surname);
free((person+i)->eMail);
}
free(person);
free(buffer);
free(buffer2);
free(nameTimes);
free(surnameTimes);
fclose(fptr);
fclose(sptr);
return 0;
}
int whichDataType (char* buffer) {
if (buffer[0] >= 'A' && buffer[0] <= 'Z') {
if (buffer[1] >= 'a' && buffer[1] <= 'z') {
return NAME;
}
else if (buffer[1] >= 'A' && buffer[1] <= 'Z') {
return SURNAME;
}
}
else if (buffer[0] >= 'a' && buffer[0] <= 'z') {
return EMAIL;
}
else if (buffer[0] >= '0' && buffer[0] <= '9') {
return ID;
}
}
void writeData (PEOPLE* person, char* buffer, int whichData, int* nameTimes, int* surnameTimes, int personNumber) {
if (personNumber != 0) {
--personNumber;
}
switch (whichData) {
case NAME:
if (*nameTimes == 0) {
(person + personNumber)->name = (char*) malloc ( WORD_SIZE * sizeof(char));
++(*nameTimes);
}
break;
case SURNAME:
if (*surnameTimes == 0) {
(person+personNumber)->surname = (char*) malloc ( WORD_SIZE * sizeof(char));
++(*surnameTimes);
}
break;
case EMAIL:
(person + personNumber)->eMail = (char*) malloc ( WORD_SIZE * sizeof(char));
break;
}
char space[2];
strcpy(space, " ");
switch (whichData) {
case NAME:
if (*nameTimes == 0) {
strcpy( (person+personNumber)->name, buffer);
}
else {
strcat ( (person+personNumber)->name, space);
strcat( (person+personNumber)->name, buffer);
}
break;
case SURNAME:
if (*surnameTimes == 0) {
strcpy ( (person+personNumber)->surname, buffer);
}
else {
strcat( (person + personNumber)->surname, space);
strcat( (person + personNumber)->surname, buffer);
}
break;
case EMAIL:
strcpy( (person + personNumber)->eMail, buffer);
break;
case ID:
(person+personNumber)->id = atoi(buffer);
break;
}
}
void printData (PEOPLE* person, FILE* sptr, int personNumber) {
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
fprintf(sptr, "\n|%30s\t\t", "***NAME***");
fprintf(sptr, "|%30s\t\t", "***SURNAME***");
fprintf(sptr, "|%30s\t\t", "***E-MAIL***");
fprintf(sptr, "|%30s\t|\n", "***ID NUMBER***");
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
int i;
for (i = 0; i<personNumber; ++i) {
fprintf(sptr, "\n|%d%30s\t\t", i, (person+i)->name);
fprintf(sptr, "|%30s\t\t", (person+i)->surname);
fprintf(sptr, "|%30s\t\t", (person+i)->eMail);
fprintf(sptr, "|%30d\t|\n", (person+i)->id);
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
}
}
Я стараюсь malloc
Каждая новая структура и внутри нее освобождают мои буферы после того, как я закончу с ними работу и снова распределяю их для следующих. Если для одного человека существует более одного имени или фамилии, я назначаю его имя или фамилию один раз и strcpy
мой буфер в соответствующее место. Если я пойду к моему writeData
функция имени или фамилии снова для того же человека, я передаю выделенную память, потому что я уже сделал это. Затем я в основном объединяю свой новый буфер (имя или фамилию) рядом со старым.
У меня вопрос: почему я получаю эти недопустимые символы, где я допустил ошибку и как ее предотвратить?
1 ответ
Я увидел проблему и решил ее. Возникла проблема с алгоритмом. Когда программа переходит к выделению памяти для имени, чтобы не выделять память снова для строки имени человека, когда речь идет о втором имени, чтобы не потерять первое, я увеличивал nameTimes один раз. Затем при втором переключателе, так как это имя, он должен ввести if (*nameTimes == 0)
часть к strcpy
, Но так как я уже увеличивал его при выделении, он никогда не входил в эту часть и всегда использовал strcat для копирования строки. Но не было последовательности для объединения, что вызывало проблемы. Я изменил состояние этой части на if (*nameTimes == 1)
, Затем возникла вторая проблема, заключающаяся в том, что она просто печатала фамилию только потому, что я не увеличивала ее снова, поэтому она застряла на strcpy
часть. Так что я снова увеличил его после strcpy
, То же самое касается фамилии. Я также улучшил код благодаря @Barmar и @ user3629249.
| Новый Кодекс |
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_SIZE 30
#define NAME 1
#define SURNAME 2
#define EMAIL 3
#define ID 4
typedef struct ppl {
char* name;
char* surname;
char* eMail;
int id;
} PEOPLE;
int whichDataType (char* buffer);
void writeData (PEOPLE* person, char* buffer, int whichData, int* nameTimes, int* surnameTimes, int personNumber);
void printData (PEOPLE* person, FILE* sptr, int personNumber);
int main (void) {
FILE* fptr = NULL;
fptr = fopen("disorganized.txt", "r");
if (fptr == NULL) {
perror("Error: ");
exit( EXIT_FAILURE );
}
FILE* sptr = NULL;
sptr = fopen("organized.txt", "w");
if (sptr == NULL) {
perror("Error: ");
exit( EXIT_FAILURE );
}
int whichData;
int personNumber = 0;
int nameTimes = 0;
int surnameTimes = 0;
int forOnce = 0;
char* buffer = NULL;
int* buffer2 = NULL;
PEOPLE* person = NULL;
PEOPLE* realloctemp = NULL;
person = malloc (sizeof(PEOPLE));
if ( person == NULL ) {
perror("Error, malloc failed for person. ");
exit ( EXIT_FAILURE );
}
buffer = malloc ( WORD_SIZE * sizeof(char));
if ( buffer == NULL ) {
perror("Error, malloc failed for buffer. ");
exit ( EXIT_FAILURE );
}
while ((fscanf(fptr, "%29s", buffer)) == 1) {
if (personNumber != 0) {
realloctemp = realloc (person, personNumber * sizeof(PEOPLE));
if ( realloctemp == NULL ) {
perror("Error, reallocating. ");
exit ( EXIT_FAILURE );
}
else {
person = realloctemp;
}
}
whichData = whichDataType(buffer);
writeData(person, buffer, whichData, &nameTimes, &surnameTimes, personNumber);
buffer2 = malloc (sizeof(int));
if ( buffer2 == NULL ) {
perror("Error, malloc failed for buffer2. ");
exit ( EXIT_FAILURE );
}
else {
*buffer2 = fgetc(fptr);
}
if (*buffer2 == '\n') {
if (forOnce == 0) {
personNumber = personNumber + 2;
free(buffer2);
free(buffer);
buffer = malloc ( WORD_SIZE * sizeof(char));
if ( buffer == NULL ) {
perror("Error*, malloc failed for buffer. ");
exit ( EXIT_FAILURE );
}
nameTimes = 0;
surnameTimes = 0;
++forOnce;
}
else {
++personNumber;
free(buffer2);
free(buffer);
buffer = malloc ( WORD_SIZE * sizeof(char));
if ( buffer == NULL ) {
perror("Error**, malloc failed for buffer. ");
exit ( EXIT_FAILURE );
}
nameTimes = 0;
surnameTimes = 0;
}
}
else if (*buffer2 == ' ' || *buffer2 == '\t') {
free(buffer2);
free(buffer);
buffer = malloc ( WORD_SIZE * sizeof(char));
if ( buffer == NULL ) {
perror("Error***, malloc failed for buffer. ");
exit ( EXIT_FAILURE );
}
}
}
--personNumber;
printData (person, sptr, personNumber);
int i;
for (i = 0; i<personNumber; ++i) {
free((person+i)->name);
free((person+i)->surname);
free((person+i)->eMail);
}
free(person);
free(buffer);
free(buffer2);
fclose(fptr);
fclose(sptr);
return EXIT_SUCCESS;
}
int whichDataType (char* buffer) {
if (buffer[0] >= 'A' && buffer[0] <= 'Z') {
if (buffer[1] >= 'a' && buffer[1] <= 'z') {
return NAME;
}
else if (buffer[1] >= 'A' && buffer[1] <= 'Z') {
return SURNAME;
}
}
else if (buffer[0] >= 'a' && buffer[0] <= 'z') {
return EMAIL;
}
else if (buffer[0] >= '0' && buffer[0] <= '9') {
return ID;
}
else {
perror("Invalid data type. ");
exit( EXIT_FAILURE );
}
}
void writeData (PEOPLE* person, char* buffer, int whichData, int* nameTimes, int* surnameTimes, int personNumber) {
if (personNumber != 0) {
--personNumber;
}
switch (whichData) {
case NAME:
if (*nameTimes == 0) {
(person + personNumber)->name = malloc ( WORD_SIZE * sizeof(char));
if ( (person+personNumber)->name == NULL ) {
perror("Error. malloc failed for (person+personNumber)->name");
exit ( EXIT_FAILURE );
}
++(*nameTimes);
}
break;
case SURNAME:
if (*surnameTimes == 0) {
(person+personNumber)->surname = malloc ( WORD_SIZE * sizeof(char));
if ( (person+personNumber)->surname == NULL ) {
perror("Error. malloc failed for (person+personNumber)->surname");
exit ( EXIT_FAILURE );
}
++(*surnameTimes);
}
break;
case EMAIL:
(person + personNumber)->eMail = malloc ( WORD_SIZE * sizeof(char));
if ( (person+personNumber)->eMail == NULL ) {
perror("Error. malloc failed for (person+personNumber)->eMail");
exit ( EXIT_FAILURE );
}
break;
}
char space[2];
strcpy(space, " ");
switch (whichData) {
case NAME:
if (*nameTimes == 1) {
strcpy( (person+personNumber)->name, buffer);
++(*nameTimes);
}
else if (*nameTimes>1) {
strcat ( (person+personNumber)->name, space);
strcat( (person+personNumber)->name, buffer);
}
else {
perror("Error, invalid nameTimes value. ");
exit ( EXIT_FAILURE );
}
break;
case SURNAME:
if (*surnameTimes == 1) {
strcpy ( (person+personNumber)->surname, buffer);
++(*surnameTimes);
}
else if (*surnameTimes>1) {
strcat( (person + personNumber)->surname, space);
strcat( (person + personNumber)->surname, buffer);
}
else {
perror("Error, invalid surnameTimes value. ");
exit ( EXIT_FAILURE );
}
break;
case EMAIL:
strcpy( (person + personNumber)->eMail, buffer);
break;
case ID:
(person+personNumber)->id = atoi(buffer);
break;
}
}
void printData (PEOPLE* person, FILE* sptr, int personNumber) {
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
fprintf(sptr, "\n|%30s\t\t", "***NAME***");
fprintf(sptr, "|%30s\t\t", "***SURNAME***");
fprintf(sptr, "|%30s\t\t", "***E-MAIL***");
fprintf(sptr, "|%30s\t|\n", "***ID NUMBER***");
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
int i;
for (i = 0; i<personNumber; ++i) {
fprintf(sptr, "\n|%d%30s\t\t", i+1, (person+i)->name);
fprintf(sptr, "|%30s\t\t", (person+i)->surname);
fprintf(sptr, "|%30s\t\t", (person+i)->eMail);
fprintf(sptr, "|%30d\t|\n", (person+i)->id);
fprintf(sptr, "-------------------------------------------------------------------------------------------------------------------------------------------------------------------");
}
}