#c #file #strlen #fgetc #file-pointer
#c #файл #strlen #fgetc #указатель на файл
Вопрос:
Во-первых, позвольте мне сказать, что я прошу прощения за отсутствие конкретики в этом названии. Честно говоря, не было хорошего способа описать то, с чем я столкнулся, в одном предложении, если честно, но я постараюсь описать это как можно лучше.
Я экспериментировал с использованием функций обработки файлов C. Я тестировал способы применения функции fgetc к моему назначению структур данных, над которым я работаю для колледжа. Я без особых трудностей понял, как я собираюсь его использовать, но затем я столкнулся с чем-то странным, когда тестировал разные выходные данные кода.
По сути, я пытался извлечь имя и фамилию человека из текстового файла, который мой профессор дал как часть задания. Мне удалось это сделать, но я заметил, как изменился вывод массива строк / символов в зависимости от того, как и где он выполнялся
Ниже приведен код, который выполняется:
FILE *fptr;
char c;
char name[20];
int pos = 0; //integer representing position of char to be written in name char array
// Open file
fptr = fopen("Anomaly.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file n");
exit(0);
}
// Read contents from file
//27th character is last letter of first line. After that there is a newline character.
//So technically, after 28 characters we will have the second line's characters
for (int i = 0; i < 28; i ) //ignores the first line as it does not contain customer information
{
c = fgetc(fptr);
}
c = fgetc(fptr); //char c = first character in the second line (which is 'R')
while (isprint(c) != 0) //Read characters until a non-printable character is reached
{
name[pos ] = c;
c = fgetc(fptr);
}
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
name[pos] = ''; //Basically truncating the string with this here
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
//Close File
fclose(fptr);
Когда я запускаю приведенный выше код только внутри основной функции, на экране выводится следующее:
----------------------------Beginning of Main:
Rose King§@
Pos: 9 Strlength: 11
Rose King
Pos: 9 Strlength: 9
----------------------------End of Main
Однако, если я помещаю тот же код внутри функции, которую я вызвал «fromFunc», и вызываю свою основную функцию fromFunc, это то, что выводится вместо этого:
----------------------------Beginning of fromFunc
Rose King
Pos: 9 Strlength: 9
Rose King
Pos: 9 Strlength: 9
----------------------------End of fromFunc
Я не могу понять, почему это происходит. Я попытался сделать все мои переменные глобальными, что ничего не изменило. Я пробовал передавать значения по указателю и по ссылке на функцию; вывод все равно не изменился. В настоящее время я использую Codeblocks 20.03 с компилятором GNU GCC, чтобы проверить это, поэтому я не могу сказать, происходит ли это с другими IDE или компиляторами. При необходимости содержимое используемого мной текстового файла показано ниже:
Name Mileage Years Sequence
Rose King 93000 2 1
И для потомков, вот весь исходный код:
#include <stdio.h>
#include <stdlib.h> // For exit()
#include <string.h>
void fromFunc()
{
printf("----------------------------Beginning of fromFuncn");
FILE *fptr;
char c;
char name[20];
int pos = 0; //integer representing position of char to be written in name char array
// Open file
fptr = fopen("Anomaly.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file n");
exit(0);
}
// Read contents from file
//27th character is last letter of first line. After that there is a newline character.
//So technically, after 28 characters we will have the second line's characters
for (int i = 0; i < 28; i ) //ignores the first line as it does not contain customer information
{
c = fgetc(fptr);
}
c = fgetc(fptr); //char c = first character in the second line (which is 'R')
while (isprint(c) != 0) //Read characters until a non-printable character is reached
{
name[pos ] = c;
c = fgetc(fptr);
}
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
name[pos] = '';
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
//Close File
fclose(fptr);
printf("----------------------------End of fromFuncn");
}
int main()
{
fromFunc();
printf("----------------------------Beginning of Main:n");
{
FILE *fptr;
char c;
char name[20];
int pos = 0; //integer representing position of char to be written in name char array
// Open file
fptr = fopen("Anomaly.txt", "r");
if (fptr == NULL)
{
printf("Cannot open file n");
exit(0);
}
for (int i = 0; i < 28; i ) //ignore the first line as it does not contain customer information
{
c = fgetc(fptr);
//printf ("%c", c);
}
c = fgetc(fptr); //char c = first character in the second line (which is 'R')
while (isprint(c) != 0)
{
name[pos ] = c; //pos is in brackets here because it saves an extra line. Without it, we'd have to add pos at the end of the while loop
c = fgetc(fptr);
}
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
name[pos] = '';
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
fclose(fptr);
}
printf("----------------------------End of Mainn");
return 0;
}
Комментарии:
1. Вы печатаете
name
до того, как он завершается нулевым значением.2. Переменные могут иметь случайные значения по умолчанию, в зависимости от того, как чувствует себя компилятор в тот день. В
main
вы не получили нулевой терминатор после 9 символов. ВfromFunc
вы сделали — потому что это случайно
Ответ №1:
Вы вызвали неопределенное поведение, используя значения неинициализированной нестатической локальной переменной name[pos]
, которая является неопределенной, для первой printf("%sn", name);
в каждой функции.
При вызове неопределенного поведения допускается все, что угодно.
Ответ №2:
Вы должны явно сохранить нулевой байт в конце name
массива с name[pos] = '';
после циклов чтения. Без этого строка может быть неправильно завершена нулем, поскольку name
это локальный неинициализированный объект, его элементы неопределенны. Иногда name[pos]
случается, что у вас уже есть нулевой байт, иногда нет, как вы заметили, это называется неопределенным поведением.
Вот модифицированная версия:
#include <stdio.h>
#include <stdlib.h> // For exit()
#include <string.h>
void fromFunc() [
printf("----------------------------Beginning of fromFuncn");
FILE *fptr;
int c;
char name[20];
int pos = 0; //integer representing position of char to be written in name char array
// Open file
fptr = fopen("Anomaly.txt", "r");
if (fptr == NULL) {
printf("Cannot open file n");
exit(0);
}
// Read contents from file
//27th character is last letter of first line. After that there is a newline character.
//So technically, after 28 characters we will have the second line's characters
for (int i = 0; i < 28; i ) { //ignores the first line as it does not contain customer information
c = fgetc(fptr);
}
c = fgetc(fptr); //char c = first character in the second line (which is 'R')
while (pos < 19 amp;amp; isprint(c) != 0) { //Read characters until a non-printable character is reached
name[pos ] = c;
c = fgetc(fptr);
}
name[pos] = '';
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
//Close File
fclose(fptr);
printf("----------------------------End of fromFuncn");
}
int main()
{
fromFunc();
printf("----------------------------Beginning of Main:n");
{
FILE *fptr;
int c;
char name[20];
int pos = 0; //integer representing position of char to be written in name char array
// Open file
fptr = fopen("Anomaly.txt", "r");
if (fptr == NULL) {
printf("Cannot open file n");
exit(0);
}
for (int i = 0; i < 28; i ) { //ignore the first line as it does not contain customer information
c = fgetc(fptr);
//printf ("%c", c);
}
c = fgetc(fptr); //char c = first character in the second line (which is 'R')
while (pos < 1 amp;amp; isprint(c) != 0) {
name[pos ] = c; //pos is in brackets here because it saves an extra line. Without it, we'd have to add pos at the end of the while loop
c = fgetc(fptr);
}
name[pos] = '';
printf("%sn", name);
printf("Pos: %d Strlength: %dn", pos, strlen(name));
fclose(fptr);
}
printf("----------------------------End of Mainn");
return 0;
}