Задача состояла в том, чтобы прочитать первые 20 строк из определенного файла и отформатировать их, чтобы использовать только определенные части, следующим шагом было сохранить эти отформатированные строки в динамическом массиве (char ** str
| указатель на указатель), отправить его в функцию и распечатайте его с помощью указанной функции
Вот основной код:
int main(int argc, char* argv[]){
FILE* file = fopen("./passwd.txt", "r"); // open file
if (!file)
{
perror("Error opening file");
return 1;
}
char line [MAXCHARS];
int counter = 0;
char ** str;
str = malloc(20 * sizeof (char*));
while (fgets(line, MAXCHARS, file) && counter < 20) {
char * position;
if ((position = strchr(line,':'))){
char * end_char;
*position = 0; //setting here the value 0, will terminate the string line (first column)
if ((position = strchr(++position,':')) && (end_char = strchr(++position,':'))){ //increment the position to skip the second column
*end_char = 0; //set the value 0 to end_char to terminate the string pointed by position
char * temp_str = "\0";
sprintf(temp_str, "{%d} - {%s}\n", atoi(position), line ); //concatenate line and userID into one string and store it into a temporary string
*(str + counter) = malloc(sizeof (char) * strlen(temp_str)); //set the memory space for the temp_string into the array
*(str + counter) = temp_str; //copy the string into the array
}
}
counter++;
}
printArray(str);
fclose(file);
if (line)
free(line);
return 0;
}
А вот функция печати:
void printArray(char ** array){
for(int i = 0; i < 20; i++){
printf("%s",*(array+i));
free(*(array+i));
}
free(array);
}
Я не могу найти ошибку, код компилируется с
Process finished with exit code -1073741819 (0xC0000005)
Так что, по крайней мере, он компилируется, и я думаю, что это просто проблема с моими навыками обработки указателей, но я не могу найти ошибку.
Кто-нибудь может мне помочь?
sprintf(temp_str,...
— вы печатаете в строковый литерал, что само по себе является неопределенным поведением, более того, весьма вероятно, что недоступный для записи буфер слишком короткий...
free(line);
неправильно: вы не выделили line
@Aconcagua, тогда как я могу сохранить с определенной строкой формата? потому что гугление всегда приводило меня к функции sprintf().
@Mathieu, что бесплатно (строка) была частью предыдущей задачи, просто забыл ее удалить
Для *(str + x)
есть короткая рука: str[x]
— но вы не копирование в str[counter]
, а вместо этого переназначаете временную строку, теряя указатель на только что выделенную временную, при этом массив будет содержать во всех полях один и тот же адрес tmp_str
. Вместо этого вам нужно strcpy(str[counter], tmp_str)
— или более эффективно: size_t len = strlen(tmp); malloc(tmp); memcpy(str[c], tmp, len + 1);
избегать многократного рассмотрения нулевого символа (strlen
и strcpy
).
@SimoneNardone sprintf
в порядке, а не в буфере. Вам необходимо выделить достаточно памяти, например. грамм. через char tmp_str[MaximumExpectedLength];
. Спецификатор формата для строки может учитывать максимальную длину строки, если вы хотите быть в безопасности (предотвращая запись за пределы буфера).
Хорошо, спасибо большое всем, теперь я понял.
Дополнительное примечание: в системе POSIX вы можете использовать strdup
для удобства — обратите внимание, что тогда ваш код является переносимым нет (по крайней мере, до C23, который будет включать его).
в вашей программе 3 ошибки:
используйте temp_str, которые не были выделены.
char * temp_str = "\0";
sprintf(temp_str, "{%d} - {%s}\n", atoi(position), line );
сохранить temp_str
адрес локального указателя в str+counter
и использовать указатель после того, как он вышел из области действия в printArray
=> поведение undefined
line
не указатель, нельзя использовать free
if (line)
{
free(line);
}
давайте попробуем это. https://godbolt.org/z/7KPfnTEMY Я исправляю эти пункты
Потом ошибка была с выделением памяти, забыл правильно выделить, Спасибо большое.
Просто чтобы быть точным: хранение адреса локальной переменной в массиве не является неопределенным поведением, но чтение этого указателя после того, как эта локальная переменная вышла из области видимости, является...
И что еще хуже: str[counter] = malloc(); str[counter] = tmp_str;
<- утечка памяти, теряется последний указатель на только что выделенную память.
@Aconcagua, да, спасибо, использование указателя, который вышел за рамки, - это UB. я исправлю это
@Aconcagua printArray
освободит их.
@long.kl Не в исходной версии — адрес вновь выделенной памяти перезаписывается в выражении, сразу после присваивания tmp_str
— printArray
попытается освободить временную память (несколько раз!). Это меняется с вашей версией, где вы правильно strcpy
данные из временной памяти в эту вновь выделенную память.