溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄

發(fā)布時(shí)間:2020-06-24 06:51:58 來源:網(wǎng)絡(luò) 閱讀:383 作者:wx5de7b5143d243 欄目:編程語言

項(xiàng)目需求

實(shí)現(xiàn)多個(gè)賬號(hào)

項(xiàng)目實(shí)現(xiàn)

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

int main(void) {
    // 定義變量,用來表示用戶名和密碼
    char name[32];
    char password[16];
    FILE *file;  //定義了一個(gè)檔指針變量,變量名是file
    char line[128];
    char name_tmp[32];
    char password_tmp[16];
    char *ret;

    //打開檔
    file = fopen("users.txt", "r");   
    if (!file) {   //等效于 file == NULL  
        printf("檔打開失敗");
        return 1;
    }

    //輸入用戶名和密碼
    while (1) {
        // 輸入用戶名和密碼
        printf("請(qǐng)輸入用戶名:");
        scanf("%s", name);
        printf("請(qǐng)輸入密碼:");
        scanf("%s", password);

        /*
        if (strcmp(name, "admin") == 0 && 
            strcmp(password, "123456") == 0) {
            break;
        } else {
            printf("用戶名或密碼錯(cuò)誤!\n");  
            system("pause");
            system("cls");
        }
        */  

        //從檔中讀取賬號(hào),并進(jìn)行判斷!
        while (1) {
            //讀一行
            ret = fgets(line, sizeof(line), file); //line:  "admin 123456\n"
            if (!ret) {
                break;
            }           
            sscanf(line, "%s %s", name_tmp, password_tmp);
            if (!strcmp(name, name_tmp) && !strcmp(password, password_tmp)) {
                break;
            }
        }

        if (ret) {  //用戶名和密碼匹配成功
            break;
        } else {
            printf("用戶名或密碼錯(cuò)誤!\n");  
            system("pause");
            system("cls");

            fseek(file, 0, SEEK_SET); //把檔內(nèi)部的位置指針設(shè)置到檔頭
        }
    }

    system("cls");

    // 打印功能菜單
    printf("---交換機(jī)后臺(tái)管理---\n");
    printf("1. 創(chuàng)建賬號(hào)\n");
    printf("2. IP管理\n");
    printf("3. 退出\n");
    printf("請(qǐng)選擇...");

    return 0;
}

項(xiàng)目精講

1.fopen檔的打開操作
函數(shù)原型
#include <stdio.h>
FILE fopen( const char fname, const char mode );
參數(shù)1:fname 表示文件名(可以含有路徑信息)
參數(shù)2:打開方式
返回值:FILE
檔指針,
如果打開失敗,就返回NULL(就是0)

mode 打開方式
"r" 以“讀”的方式打開一個(gè)文本檔(只能讀)
"r+" 與"r" 的區(qū)別在于,增加了“寫”
"rb" 以“讀”的方式打開一個(gè)二進(jìn)制檔(只能讀)
"rb+" 與"rb"的區(qū)別在于,增加了“寫”

"w" 以“寫”的方式創(chuàng)建一個(gè)文本檔,如果這個(gè)檔已經(jīng)存在,就會(huì)覆蓋原來的檔
"w+" 與"w"的區(qū)別在于,增加了“讀”
"wb" 以“寫“的方式創(chuàng)建一個(gè)二進(jìn)制檔
"wb+" 與"wb"的區(qū)別在于,增加了“讀”

"a" 以“尾部追加”的方式打開一個(gè)文本檔, (只能寫)
"a+" 以"a"的區(qū)別在于,增加了"讀"
"ab" 以“尾部追加”的方式打開一個(gè)二進(jìn)制檔, (只能寫)
"ab+" 與"ab"的區(qū)別在于,增加了“讀”

小結(jié):
打開方式,共1到3個(gè)字符。
第一個(gè)字符是 r、w或a
r 表示“讀”,用于打開已經(jīng)存在的檔
w 表示“創(chuàng)建”, 用于創(chuàng)建一個(gè)新檔,并能夠“寫”
a 表示“尾部追加”,并能夠"寫"

b, 只能寫在第二位,表示打開的是二進(jìn)制檔
+,只能寫在最后,表示增加一個(gè)讀或?qū)懙墓δ?/p>

實(shí)例

#include <stdio.h>

int main(void) {
    FILE *file;

    //file = fopen("users.txt", "r");
    file = fopen("users1.txt", "r");
    if (file != NULL) {  //NULL就是0
        printf("檔users.txt打開成功!\n");
    } else {
        printf("檔users.txt打開失敗!\n");
    }

    return 0;
}

2.fclose檔的關(guān)閉操作

清理緩沖區(qū),并釋放檔指針。

Demo

#include <stdio.h>

int main(void) {
    FILE *file;

    file = fopen("users.txt", "a");
    fputs("\nxiaoxiao 123456",  file);

    fclose(file);
    return 0;
}

特別注意:
對(duì)檔執(zhí)行寫操作以后,并不會(huì)馬上寫入檔,而只是寫入到了這個(gè)檔的輸出緩沖區(qū)中!
只有當(dāng)這個(gè)輸出緩沖區(qū)滿了,或者執(zhí)行了fflush,或者執(zhí)行了fclose函數(shù)以后,或者程序結(jié)束,
才會(huì)把輸出緩沖區(qū)中的內(nèi)容正真寫入檔!

3.fgetc檔的讀操作

函數(shù)原型:
#include <stdio.h>
int fgetc( FILE *stream );
返回值:成功時(shí),返回讀到的字符,返回的是int類型(實(shí)際值是字符)
失敗或讀到檔尾,返回EOF (就是-1)

作用:
從檔中讀取一個(gè)字符

實(shí)例:

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;

    file = fopen("users.txt", "r");

    while ((c = fgetc(file)) != EOF) {  //EOF就是 -1
        printf("%c", c);
    }

    return 0;
}

4.fputc寫一個(gè)字符到檔fputc

函數(shù)原型:
#include <stdio.h>
int fputc( int ch, FILE *stream );

實(shí)例:
test.c

#include <stdio.h>

int main(void) {
    FILE *file1;
    FILE *file2;
    char c;

    file1 = fopen("test.c", "r");
    file2 = fopen("test2.c", "w");

    while ((c = fgetc(file1)) != EOF) {  //EOF就是 -1
        fputc(c, file2);
    }

    fclose(file1);
    fclose(file2);

    return 0;
}

5.fgets 從檔中讀取一個(gè)字符串

復(fù)習(xí):
在項(xiàng)目4的“字符串輸入”中學(xué)習(xí)過。

函數(shù)原型:
#include <stdio.h>
char fgets( char str, int num, FILE *stream );
參數(shù):
num: 最多讀取num-1個(gè)字符,或者遇到檔結(jié)束符EOF為止(即“檔讀完了”)
返回值; 讀取失敗時(shí), 返回NULL,
讀取成功時(shí),返回str

實(shí)例:

#include <stdio.h>

int main(void) {
    FILE *file1;
    char tmp[64];

    char c;

    file1 = fopen("test.c", "r");

    while (fgets(tmp, sizeof(tmp), file1) != NULL) { 
        printf("%s", tmp);
    }

    fclose(file1);
    return 0;
}

6.fputs 寫一個(gè)字符串到檔中去

函數(shù)原型:
#include <stdio.h>
int fputs( const char str, FILE stream );

實(shí)例

#include <stdio.h>

int main(void) {
    FILE *file1;
    FILE *file2;
    char tmp[64];

    char c;

    file1 = fopen("test.c", "r");
    file2 = fopen("test2.c", "w");

    while (fgets(tmp, sizeof(tmp), file1) != NULL) { 
        fputs(tmp, file2);
    }

    fclose(file1);
    fclose(file2);
    return 0;
}

7.fprintf 往檔中寫格式化數(shù)據(jù)

函數(shù)原型:
#include <stdio.h>
int fprintf( FILE stream, const char format, ... );

Demo:

#include <stdio.h>

int main(void) {
    FILE *file1;
    char name[32];
    int age;
    char c;

    file1 = fopen("info.txt", "w");

    while (1) {
        printf("請(qǐng)輸入學(xué)員姓名:");
        scanf("%s", name);
        printf("請(qǐng)輸入%s的成績(jī): ", name);
        scanf("%d", &age);

        fprintf(file1, "姓名:%s\t\t年齡:%d\n", name, age);

        printf("還需要繼續(xù)輸入嗎? Y/N\n");

        //fflush(stdin);
        while((c=getchar()) != '\n');  //直到讀到回車符為止! 

        scanf("%c", &c);
        if (c == 'Y' || c == 'y') {
            continue;
        } else {
            break;
        }
    }

    fclose(file1);
    return 0;
}

8.fscanf 格式化讀取檔中數(shù)據(jù)

函數(shù)原型:
#include <stdio.h>
int fscanf( FILE stream, const char format, ... );
返回值:成功時(shí),返回實(shí)際讀取的數(shù)據(jù)個(gè)數(shù)
失敗時(shí),返回 EOF (-1)
匹配失敗時(shí),返回0

Demo

#include <stdio.h>

int main(void) {
    FILE *file1;
    char name[32];
    int age;
    int ret;

    file1 = fopen("info.txt", "r");

    while (1) {
        ret = fscanf(file1, "姓名:%s 年齡:%d\n", &name, &age);
        if (ret == EOF) {
            break;
        }

        printf("%s,%d\n", name, age);
    }

    fclose(file1);
    return 0;
}

9.fwrite 以二進(jìn)制形式寫數(shù)據(jù)到檔中去

#include <stdio.h>
int fwrite( const void buffer, //要寫入的數(shù)據(jù)的其實(shí)地址,也就是變量的地址
size_t size, //每“塊”數(shù)據(jù)的大小
size_t count, //寫入幾塊數(shù)據(jù)
FILE
stream );

Demo

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

int main(void) {
    FILE *file1;
    char name[32];
    int age;
    int ret;

    file1 = fopen("info.txt", "wb");

    printf("請(qǐng)輸入您的姓名: ");
    gets(name);
    printf("請(qǐng)輸入您的年齡: ");
    scanf("%d", &age);

    fwrite(name, sizeof(name), sizeof(char), file1);
    fwrite(&age, 1, sizeof(int), file1);

    fclose(file1);
    return 0;
}

【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄
補(bǔ)充:
w和wb的區(qū)別
wb的demo

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

int main(void) {
    FILE *file1;
    char info[] = "Hello\nWorld";
    int age;
    int ret;

    file1 = fopen("test.txt", "wb");

    fwrite(info,  sizeof(char), strlen(info),  file1);

    fclose(file1);
    return 0;
}

【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄
w的demo

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

int main(void) {
    FILE *file1;
    char info[] = "Hello\nWorld";   // \n 保存位  \r\n
    int age;
    int ret;

    file1 = fopen("test.txt", "w");

    fwrite(info, strlen(info), sizeof(char), file1);

    fclose(file1);
    return 0;
}

【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄
小結(jié):
在windows平臺(tái)下,
當(dāng)使用w方式打開檔時(shí),
如果使用fwrite寫入數(shù)據(jù)時(shí),會(huì)把’\n’寫入為 ‘\r’’\n’
即把10保存為 13 10
因?yàn)椋趙indows平臺(tái)下,文本檔中的回車符\n,會(huì)保存為 \r\n
( \n的ASCII碼為10, \r的ASCII碼為13)

當(dāng)使用wb方式打開檔時(shí),
如果使用fwrite寫入數(shù)據(jù)時(shí),遇到’\n’仍只寫入為 ‘\n’

fread 以二進(jìn)制形式讀取檔中的數(shù)據(jù)

函數(shù)原型:
#include <stdio.h>
int fread( void buffer, size_t size, size_t num, FILE stream );

Demo

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

int main(void) {
    FILE *file1;
    char name[32];
    int age;
    int ret;

    file1 = fopen("student.txt", "rb");

    fread(name, sizeof(name), sizeof(char), file1);
    fread(&age, 1, sizeof(int), file1);

    printf("%s, %d\n", name, age);

    fclose(file1);
    return 0;
}

putw 以二進(jìn)制形式存貯一個(gè)整數(shù)

demo

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

int main(void) {
    FILE *file1;
    int data[] = {1,2,3,4,5};
    int i;

    file1 = fopen("test.txt", "w");

    for (i=0; i<5; i++) {
        putw(data[i], file1);
    }   

    fclose(file1);

    return 0;
}

【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄

getw 以二進(jìn)制形式讀取一個(gè)整數(shù)

函數(shù)原型:
int getw(FILE *fp)
返回值:成功時(shí)返回讀取到的值
失敗時(shí)返回-1。

Demo

#include <stdio.h>

int main(void) {
    FILE *file;
    int value;

    file = fopen("test.data", "rb");
    if (!file) {
        printf("檔打開失敗!\n");
        return 1;
    }

    while (1) {
        value = getw(file); 
        if (value == -1 && feof(file)) {
            break;
        }

        printf("%d ", value);
    }

    fclose(file);

    return 0;
}

檔狀態(tài)檢查函數(shù)

feof 檔結(jié)束

函數(shù)原型:
#include <stdio.h>
int feof( FILE *stream );
返回值:如果指定的程序,已經(jīng)到達(dá)檔末尾位置,就返回非零值(真)。

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;

    file = fopen("test.c", "r");

    //while ((c = fgetc(file)) != EOF) {  //EOF就是 -1
    while (!feof(file)) {
        c = fgetc(file);
        printf("%c", c);
    }

    return 0;
}

ferror 檔讀/寫出錯(cuò)

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;
    int ret;

    file = fopen("test.c", "r");

    fputc('A', file);

    if (ferror(file)) {
        perror("檔file發(fā)生錯(cuò)誤");
    }

    return 0;
}

執(zhí)行結(jié)果:
【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄
把 “r” 改為 “r+” 就不會(huì)發(fā)生錯(cuò)誤了。

clearerr 清除檔錯(cuò)誤標(biāo)志

函數(shù)原型:
#include <stdio.h>
void clearerr( FILE *stream );

Demo

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;
    int ret;

    file = fopen("test.c", "r");

    fputc('A', file);
    if (ferror(file)) {
        perror("檔file發(fā)生錯(cuò)誤");
    }

    //如果不清除檔錯(cuò)誤,以后讀寫檔時(shí), 即使沒有發(fā)生錯(cuò)誤,ferror仍將返回非零值(認(rèn)為還有錯(cuò))
    clearerr(file);

    c = fgetc(file);
    printf("c=%c\n", c);
    if (ferror(file)) {
        perror("檔file發(fā)生錯(cuò)誤");
    }

    return 0;
}

ftell 獲取檔指針的當(dāng)前位置

函數(shù)原型:
#include <stdio.h>
long ftell( FILE *stream );

Demo

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;
    int ret;
    long  offset;

    file = fopen("test.c", "r");

    offset = ftell(file);
    printf("當(dāng)前位置是: %ld\n", offset);

    fgetc(file);
    offset = ftell(file);
    printf("當(dāng)前位置是: %ld\n", offset);

    fclose(file);

    return 0;
}

檔定位函數(shù)

注意:檔始終只能從當(dāng)前的位置向檔尾方向讀寫!

fseek 隨機(jī)定位

函數(shù)原型:
#include <stdio.h>
int fseek( FILE *stream, long offset, int origin );

參數(shù)2:
偏移量,可正可負(fù)。
<0 向檔頭方向偏移 <>
<0 向檔尾方向偏移 <>

參數(shù)3:
SEEK_SET 從檔的開始位置定位, 此時(shí)參數(shù)2必須大于0
SEEK_CUR 從檔的當(dāng)前位置定位
SEEK_END 從檔的結(jié)束位置定位, 此時(shí)參數(shù)2必須小與0

Demo

#include <stdio.h>

int main(void) {
    FILE *file;
    char c;
    char buff[256];
    int i;

    file = fopen("test.c", "r");

    //讀取檔最后10個(gè)字符
    fseek(file, -10, SEEK_END);
    while (!feof(file)) {
        c = fgetc(file);
        printf("%c", c);
    }

    //讀取檔的第一行
    fseek(file, 0, SEEK_SET);
    fgets(buff, sizeof(buff), file);
    printf("\n第一行:%s\n", buff);

    //讀取當(dāng)前位置的前10個(gè)字符
    fseek(file, -10, SEEK_CUR);
    printf("\n這10個(gè)字符是:");
    for (i=0; i<10; i++) {
        c = fgetc(file);
        printf("%c", c);
    }

    close(file);
    return 0;
}

rewind 反繞

把檔的位置指針定位到開始位置。

rewind(file)
等效于:
fseek(file, 0, SEEK_SET)

項(xiàng)目練習(xí)

1.練習(xí)1
獨(dú)立實(shí)現(xiàn)項(xiàng)目7.

編寫一個(gè)程序,統(tǒng)計(jì)該程序本身一共有多少個(gè)字符,有多少行,并列印輸出

#include <stdio.h>

// 統(tǒng)計(jì)這個(gè)程序本身,有多少個(gè)字符,有多少行代碼

int main(void) {
    FILE *file ;
    char c;
    int count_char = 0; //字符總數(shù)
    int count_line = 0;  //行數(shù)

    file = fopen("test.c", "r");
    if (!file ) {
        printf("檔打開失敗!\n");
        return 1;
    }

    while ((c=fgetc(file)) != EOF) {
        count_char++;
        if (c == '\n') {
            count_line++;
        }
    }

    count_line++;

    printf("一共有 %d 個(gè)字符\n", count_char);
    printf("一共有 %d 行代碼\n", count_line);

    return 0;
}

3.已有一個(gè)檔,用來保存通訊錄,假設(shè)已有內(nèi)容如下:

note.txt
張三豐   Tel:13507318888  Addr:武當(dāng)
劉備     Tel:13802289999  Addr:成都
馬云     Tel:13904256666  Addr:杭州
馬化騰   Tel:13107551111  Addr:深圳

編寫一個(gè)程序,執(zhí)行效果如下:
【小白到大牛之路7】換機(jī)后臺(tái)管理之多用戶賬號(hào)登錄
參考:

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

int main(void) {
    FILE *file;
    char name_search[64];
    char line[256];
    char name[64];
    char tel[32];
    char addr[32];
    int found = 0;

    file = fopen("note.txt", "r");
    if (!file) {
        printf("檔打開失敗\n");
        return 1;
    }

    printf("請(qǐng)輸入要查詢的用戶名:");
    scanf("%s", name_search);

    while (!feof(file)) {
            fscanf(file, "%s Tel:%s Addr:%s\n", name, tel, addr);
            if (!strcmp(name, name_search)) {
                printf("%s的電話是:%s\n", name_search, tel);
                found = 1;
                break;
            }
    }

    if (found == 0) {
        printf("沒有%s的信息\n", name_search);
    }

    return 0;
}

需要特別注意fscanf的格式字符串中最后的\n,否者只能匹配第一行!

補(bǔ)充說明:

對(duì)于如下文本:
張三豐   Tel:13507318888  Addr:武當(dāng)
劉備     Tel:13802289999  Addr:成都
馬云     Tel:13904256666  Addr:杭州
馬化騰   Tel:13107551111  Addr:深圳

可以循環(huán)使用如下代碼讀?。?fscanf(file, "%s Tel:%s Addr:%s\n", name, tel, addr);

但是不加回車符,使用如下語句也能讀取:
fscanf(file, "%s Tel:%s Addr:%s", name, tel, addr);

這是是因?yàn)椋?使用fscanf(file,"%s Tel:%s Addr:%s",name_tmp,tel,addr),匹配到第一行的第2個(gè)%s時(shí),剛好把第一個(gè)行中,除了最后的回車符以外,匹配完。此時(shí)第一行還剩下一個(gè)回車符。接著進(jìn)入第2輪循環(huán),又開始使用scanf匹配,但是注意,是從檔的上一次匹配結(jié)束的位置繼續(xù)匹配,也就是第一行行尾的回車符為止,在這個(gè)格式字符串中,第一個(gè)是%s,所以會(huì)跳過第一行行尾的回車符,從而匹配成功。

如果檔的內(nèi)容是這樣的格式,就必須在格式字符串的最后加上\n了
姓名:張三豐   電話:13243879188  
姓名:張四風(fēng)   電話:13243879199

總結(jié):需要特別注意fscanf的格式字符串中最后的\n的作用。
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI