3

This code basically creates a txt file and add names and if users inputs new name it adds to txt file but it doesn't see the last letter like jack -> jac . Btw it saves names perfectly in txt file. So issue has to be at dosyaOku() .This informations must be enough but thanks to stackoverflow I need to add some more details.

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


char allFile[1000][100],userName[100];
int i = 0;

int main()
{
    addSomeNames();
    dosyaOku();
    isimAl();
    isimKarsilastir();
    dosyaOku();
    return 0;
}
void isimKarsilastir()
{
    int a,ayni = 0;
    for (a=0 ; a < i; a++)
    {
        if (strcmp(allFile[a],userName) == 0)
        {
            printf("ayni\n");
            ayni++;
        }
        else
        {
            printf("farkli\n");
        }
    }
    if (ayni>0)
    {
        printf("Kullanici adi bulunmustur\n");
    }
    else
    {
        dosyaYaz();
    }
}
void dosyaYaz()
{
    FILE * ptrfile;
    ptrfile = fopen("sondokunus.txt","a");
    fprintf(ptrfile,"\n%s",userName);
    fclose(ptrfile);

}
void isimAl()
{

    printf("Isim giriniz: ");
    gets(userName);
    printf("Girdiginiz isim: %s",userName);


}
void dosyaOku()
{

    FILE *ptrfile = NULL;
    int *ptri;
    ptri = &i;
    *ptri = 0;
    int top = 0;

    ptrfile = fopen("sondokunus.txt", "r");
    while(fgets(allFile[*ptri], 100, ptrfile))
    {
        allFile[*ptri][strlen(allFile[*ptri]) - 1] = '\0';
        *ptri += 1;
    }
    top = *ptri;
    printf("\n Dosyadaki isimler: \n");
    for(*ptri = 0; *ptri < top; *ptri += 1)
    {
        printf("%s\n", allFile[*ptri]);
    }
    fclose(ptrfile);
}
void addSomeNames()
{
    FILE * ptrfile;
    ptrfile = fopen("sondokunus.txt", "w+");
    char names[100][100];
    strcpy(names[0],"mike");
    strcpy(names[1],"joe");
    strcpy(names[2],"jack");
    for (int n=0;n <= 2; n++)
    {
        fprintf(ptrfile,"\n%s", names[n]);
    }
    fclose(ptrfile);

}
  • 2
    [Never use `gets`](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-so-dangerous-that-it-should-not-be-used) – Nate Eldredge Apr 23 '21 at 16:33
  • 3
    If the last line of your input file doesn't end with a newline character, then `allFile[*ptri][strlen(allFile[*ptri]) - 1] = '\0';` will delete the last character that it does contain. And indeed that is what happens because `addSomeNames` prints the newline before the name instead of after. – Nate Eldredge Apr 23 '21 at 16:36
  • 1
    As Nate pointed out, you're creating the file by putting the newline before the name. I'd fix that. But, _some_ `.txt` files omit the newline for the last line. A more certain way to strip an [possibly] optional newline is: `allFile[*ptri][strlen(allFile[*ptri]) - 1] = '\0';` --> `allFile[*ptri][strcspn(allFile[*ptri],"\n")] = '\0';` – Craig Estey Apr 23 '21 at 16:56
  • 1
    _Side note:_ Using `*ptri` is an unnecessary complication. You can replace all `*ptri` with just `i`. And, in this particular function, `i` doesn't need to be global [AFAICT] – Craig Estey Apr 23 '21 at 16:58

3 Answers3

2

Code has at least::

allFile[*ptri][strlen(allFile[*ptri]) - 1] = '\0'; as a problem.

When the string at allFile[*ptri] does not end with a "\n" (fairly common due to reading the last line in a text file), it lops off a non-'\n' character.

Instead

size_t length_of_string_without_linefeed = strcspn(allFile[*ptri], "\n");
allFile[*ptri][length_of_string_without_linefeed] = '\0';
// or
allFile[*ptri][strcspn(allFile[*ptri], "\n")] = '\0';

allFile[*ptri][strlen(allFile[*ptri]) - 1] is hacker exploitable.

If the first character in a line from the file is a null character, then code is like:

allFile[*ptri][(size_t)0 - 1]
// or 
allFile[*ptri][SIZE_MAX]

Which leads to undefined behavior.

Do not use - 1 with strlen(allFile[*ptri]) - 1 when strlen(allFile[*ptri]) == 0.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
1

Further to chux's answer, I would use instead:

char *p = strchr( allFile[*ptri], '\n' );
if( p ) *p = '\0';

That makes abundantly clear what you're doing, and doesn't rely on overwriting the NUL terminator if the newline isn't present.

James K. Lowden
  • 7,574
  • 1
  • 16
  • 31
  • 1
    This is another, and correct approach. Note: `line[strcspn(line, "\n\r")]=0;` can be used to lop off those pesky various end-of-lines like `'\n'`, `\r'`, `'\r\n'`, etc. that come from other systems' text formats. – chux - Reinstate Monica Apr 23 '21 at 17:49
0

As noted in other answers, dosyaOku behaves incorrectly if it gets a line that doesn't end in \n, and you should fix that. But the reason your file looks like that in the first place is probably a separate bug in addSomeNames. You have

        fprintf(ptrfile,"\n%s", names[n]);

with the newline printed before the name. This means the file will begin with a blank line, and the last line will not have \n at the end. You probably wanted to write:

        fprintf(ptrfile,"%s\n", names[n]);
Nate Eldredge
  • 48,811
  • 6
  • 54
  • 82