指针的值未被修改

编程语言 2026-07-09

最近,为了一个小项目,我需要为pwd.h写一个极简替代实现;然而,在实现一个函数时,似乎有些地方不对劲。win_pwd.h的代码是:

#ifndef _PWD_H
#define _PWD_H 1
#include <stdlib.h>
#include <stddef.h>

typedef unsigned int uid_t;
typedef unsigned int gid_t;

struct passwd{
 char * pw_name;   // User Log-in Name
 uid_t  pw_uid;    // Numerical User ID
 gid_t  pw_gid;    // Numerical Group ID
 char * pw_dir;    // Initial Working Directory
 char * pw_shell;  // Program to use as a shell
};

int getpwnam_r(const char * name, struct passwd * pwd,
               char * buffer, size_t size, struct passwd ** result){

 *result = malloc(sizeof(struct passwd));
 (* result )->pw_name = getenv("USERNAME");
 (* result )->pw_dir = getenv("PWD"); 
 (* result )->pw_shell = "powershell.exe";
 (* result )->pw_uid = 1;
 (* result )->pw_gid = 1;

 pwd = * result;
 result[0] = NULL;
 return 0;
}


#endif

而main.c的代码是:

#include "win_pwd.h"
#include <stdio.h>

int main(){
 struct passwd pwent;
 struct passwd *pwentp;
 char buf[1024];
 const char * login = "TEST";
 int lol = getpwnam_r(login, &pwent, buf, sizeof buf, &pwentp);
 printf("Username: %s\n", pwent.pw_name);
 printf("SHELL: %s\n", pwent.pw_shell);
 return 0;
}

我本以为代码会把用户名放在pwent.pw_name字段,把pwent.pw_shell字段设为powershell.exe,但两者都是空的,这让我怀疑问题出在返回了未初始化的变量。使用gdb,我发现到了getpwnam_r函数结束时,pwd的内存地址与result[0] 相同;但等到进入Username的 printf语句时,pwent的内存地址又与函数运行前一样。老实说,我已经好几年没用C 编程了,但我一直以为内存地址会这样被修改。我不太清楚我的错在哪里,若能得到帮助,我将不胜感激。

解决方案

你已经得到一个答案,指出你在按当前思路实现该函数时的错误所在。这一部分主要是关于改变这个思路。

POSIX 2024:

c int getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, struct passwd **result);

The getpwnam_r() function shall update the passwd structure pointed to by pwd and store a pointer to that structure at the location pointed to by result. The structure shall contain an entry from the user database with a matching name. Storage referenced by the structure is allocated from the memory provided with the buffer parameter, which is bufsize bytes in size. A null pointer shall be returned at the location pointed to by result on error or if the requested entry is not found.

So, if you want to mimic the real thing, getpwnam_r should not allocate memory. It should use the memory provided to it.

It could look like this:

// a helper function to append to buffer
static char* add_to_buf(char* buffer, size_t size, size_t* offset,
                        const char* str) {
    char* wr = buffer + *offset;
    *offset += snprintf(wr, size - *offset, "%s", str) + 1;

    // return pointer to beginning of the new string if it fit in the
    // remaining buffer
    return *offset < size ? wr : NULL;
}

int getpwnam_r(const char* name, struct passwd* pwd, char* buffer, size_t size,
               struct passwd** result) {
    *result = NULL;

    // lookup `name`, simulated:
    const char* USER = getenv("USERNAME");
    const char* PWD = getenv("PWD");

    // check that the user is found. note: not found is not an error
    // so return 0:
    if (!USER || !PWD) return 0;

    pwd->pw_uid = 1;
    pwd->pw_gid = 1;

    // fill buffer with the found user information:
    size_t offset = 0;

    // return ERANGE if the information does not fit in buffer:
    if (!(pwd->pw_name = add_to_buf(buffer, size, &offset, USER)))
        return ERANGE;
    if (!(pwd->pw_dir = add_to_buf(buffer, size, &offset, PWD)))
        return ERANGE;
    if (!(pwd->pw_shell = add_to_buf(buffer, size, &offset, "powershell.exe")))
        return ERANGE;

    // success
    *result = pwd;
    return 0;
}

演示

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章