You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言代码运行异常排查:fgets、strcpy_s、sprintf_s用法验证及程序逻辑问题分析

Alright, let's tackle your code's issues one by one—first that frustrating runtime quirk where it skips asking for the department, then verify those secure function usages, and finally fix other hidden bugs that might cause crashes or unexpected behavior.

1. Why the Program Skips Requesting the Department

When you use fgets(user, 20, stdin) in line 32 to read the username, it captures the newline character (\n) you enter after typing the username. This newline gets left in the input buffer, so when check_authentication runs and calls fgets(dept, 10, stdin) in line 11, it immediately reads that leftover newline as an empty input. The program doesn't pause to ask for the department because it thinks it already got input.

Fix Options:

  • Trim the newline from the username after reading it (cleanest approach):
    fgets(user, 20, stdin);
    user[strcspn(user, "\n")] = '\0'; // Removes the trailing newline
    
  • Consume leftover characters manually (avoids undefined behavior from fflush(stdin)):
    // Add this right after reading the username
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
    
2. Secure Function Usage Checks

Let's verify each secure function you're using:

strcpy_s (Line 12)

Your usage here is correct. You're passing the destination buffer size (16) which matches the malloc'd size of password_buffer, and strcpy_s will handle null termination safely. That said, you should add a check to ensure the input password (from argv[1]) isn't longer than 15 characters (since we need space for the null terminator)—otherwise strcpy_s will trigger a runtime error.

sprintf_s (Line 34)

This is a critical bug! The sprintf_s function requires the buffer size as its second parameter, but you're passing errmsg directly. This violates the function's signature and will cause undefined behavior (crashes, garbage output, etc.).

Fixed Line:

sprintf_s(outbuf, sizeof(outbuf), "%s", errmsg);

Also, line 33's sprintf_s(errmsg, "Authorised User %400s", user) is risky—%400s could overflow the buffer if combined with the prefix. Replace it with a safer format that respects the buffer size:

sprintf_s(errmsg, sizeof(errmsg), "Authorised User %s", user);

fgets (Lines 11, 32)

Usage is mostly correct, but as noted earlier, you need to trim the trailing newline from both user and dept to make string comparisons work. For example, strcmp(dept, "NSF") will never match if dept contains "NSF\n".

3. Other Hidden Issues to Fix
  • Memory Leaks: You're using malloc for password_buffer and dept but never calling free. Add these lines before returning from check_authentication:
    free(password_buffer);
    free(dept);
    
  • Malloc Failure Handling: You don't check if malloc returns NULL. If memory allocation fails, your program will crash. Add checks:
    password_buffer = (char*)malloc(16);
    if (!password_buffer) { perror("malloc failed for password_buffer"); return 0; }
    dept = (char*)malloc(10);
    if (!dept) { free(password_buffer); perror("malloc failed for dept"); return 0; }
    
  • Password as Command-Line Argument: Passing passwords via argv is a security risk—they're visible in process lists (e.g., ps on Linux, Task Manager on Windows). For better security, read the password interactively with getch or a similar function.
  • argc Check Placement: Your if (argc < 2) check is inside the username validation block. Move it to the start of main so users don't waste time entering a username only to be told they need a password.
Fixed Full Code

Here's the revised code with all fixes applied:

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

int check_authentication(char* password) {
    int auth_flag = 0;
    char* password_buffer;
    char* dept;

    // Check malloc success
    password_buffer = (char*)malloc(16);
    if (!password_buffer) {
        perror("malloc failed for password_buffer");
        return 0;
    }
    dept = (char*)malloc(10);
    if (!dept) {
        free(password_buffer);
        perror("malloc failed for dept");
        return 0;
    }

    printf("Your department? ");
    fgets(dept, 10, stdin);
    dept[strcspn(dept, "\n")] = '\0'; // Trim newline

    // Validate password length before copy
    if (strlen(password) >= 16) {
        printf("Password too long!\n");
        free(password_buffer);
        free(dept);
        return 0;
    }
    strcpy_s(password_buffer, 16, password);

    if (strcmp(password_buffer, "AsiaPacificInst") == 0 && strcmp(dept, "NSF") == 0) {
        auth_flag = 1;
    }
    if (strcmp(password_buffer, "AsiaPacificUni") == 0 && strcmp(dept, "TM") == 0) {
        auth_flag = 1;
    }

    // Clean up allocated memory
    free(password_buffer);
    free(dept);

    return auth_flag;
}

int main(int argc, char* argv[]) {
    char errmsg[512];
    char outbuf[512];
    char user[20];

    // Check for password argument first
    if (argc < 2) {
        printf("Usage: %s <password>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("Username: ");
    fgets(user, 20, stdin);
    user[strcspn(user, "\n")] = '\0'; // Trim newline

    if (strcmp(user, "Adm1n") == 0) {
        printf("Authorised User\n");
        sprintf_s(errmsg, sizeof(errmsg), "Authorised User %s", user);
        sprintf_s(outbuf, sizeof(outbuf), "%s", errmsg);

        if (check_authentication(argv[1])) {
            printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-");
            printf(" Access Granted.\n");
            printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-");
        } else {
            printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-");
            printf("\nAccess Denied.\n");
            printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-");
        }
    } else {
        printf("Unauthorised User!!\n");
        exit(EXIT_FAILURE);
    }

    return EXIT_SUCCESS;
}

内容的提问来源于stack exchange,提问作者Khohula Rhaj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 04:37:48