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

是否需要定义更多strtok函数?解析passwd内容遇编译及输出问题

问题分析与修复:解析/etc/passwd信息错位及编译警告问题

问题概述

  • 仅用户名解析正确,姓名、邮箱、主目录输出错位
  • 编译时出现「变量未使用」错误
  • 不确定strtok调用位置是否正确

用户提供的代码:

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

int main(int argc, char *argv[]) {
  if (argc != 2) {
    printf("Usage: %s <username>\n", argv[0]);
    return 1;
  }

  char *username = argv[1];

  FILE *passwd = fopen("/etc/passwd", "r");
  if (!passwd) {
    perror("fopen");
    return 1;
  }

  char *line = NULL;
  size_t max_length = 0;
  ssize_t ret_val = 0;
  char line_copy[1000];

  while ((ret_val = getline(&line, &max_length, passwd)) > 0) {
    strncpy(line_copy, line, 999);

    char *user = strtok(line_copy, ":");
    if (strcmp(user, username) == 0) {
      char *name = strtok(NULL, ":");
      char *email = strtok(NULL, ":");
      char *home_dir = strtok(NULL, ":");

      printf("user: %s\n", user);
      printf("name: %s\n", name);
      printf("email: %s\n", email);
      printf("home directory: %s\n", home_dir);
    }
  }

  fclose(passwd);
  passwd = NULL;

  return 0;
}

修复方案

1. 解决字段错位问题

/etc/passwd的标准字段顺序为:
用户名:密码占位符:UID:GID:用户全名:主目录:登录Shell
你的代码错误跳过了密码、UID、GID三个字段,直接读取后续值,导致输出错位。同时注意:/etc/passwd没有专门的邮箱字段,你可能误将「用户全名」字段当成了邮箱,该字段通常存储姓名、办公地址等备注信息,部分系统会在此填写邮箱,但不属于标准定义。

修改匹配用户名后的代码段,按正确顺序跳过无关字段:

if (strcmp(user, username) == 0) {
    // 跳过密码字段
    strtok(NULL, ":");
    // 跳过UID字段
    strtok(NULL, ":");
    // 跳过GID字段
    strtok(NULL, ":");
    // 获取用户全名(姓名)
    char *name = strtok(NULL, ":");
    // 获取主目录
    char *home_dir = strtok(NULL, ":");

    printf("user: %s\n", user);
    printf("name: %s\n", name);
    printf("home directory: %s\n", home_dir);
}

2. 解决「变量未使用」编译警告

代码中ret_val仅用于循环条件判断,部分编译器会判定为未使用;同时getline动态分配的line未释放,存在内存泄漏风险,也可能触发警告。

修复方式:

  • 用(void)变量名显式告知编译器变量已被使用
  • 释放getline分配的内存
  • 给strncpy的结果手动添加终止符,避免超长行导致的字符串异常

修改后的完整代码:

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

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Usage: %s <username>\n", argv[0]);
        return 1;
    }

    char *username = argv[1];

    FILE *passwd = fopen("/etc/passwd", "r");
    if (!passwd) {
        perror("fopen");
        return 1;
    }

    char *line = NULL;
    size_t max_length = 0;
    ssize_t ret_val = 0;
    char line_copy[1000];

    while ((ret_val = getline(&line, &max_length, passwd)) > 0) {
        // 显式标记变量已使用,消除警告
        (void)ret_val;
        (void)max_length;
        
        strncpy(line_copy, line, 999);
        // 强制添加字符串终止符,避免超长行异常
        line_copy[999] = '\0';

        char *user = strtok(line_copy, ":");
        if (user != NULL && strcmp(user, username) == 0) {
            strtok(NULL, ":"); // 跳过密码
            strtok(NULL, ":"); // 跳过UID
            strtok(NULL, ":"); // 跳过GID
            char *name = strtok(NULL, ":");
            char *home_dir = strtok(NULL, ":");

            printf("user: %s\n", user);
            printf("name: %s\n", name ? name : "N/A");
            printf("home directory: %s\n", home_dir ? home_dir : "N/A");
        }
    }

    // 释放getline分配的动态内存
    free(line);
    fclose(passwd);
    passwd = NULL;

    return 0;
}

内容的提问来源于stack exchange,提问作者Oloyede Adejayan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:50:19