【问题标题】:Cannot create a file when using malloced char arrays使用 malloced char 数组时无法创建文件
【发布时间】:2021-06-05 11:04:46
【问题描述】:

我正在按照this 文章编写标准 C 中的 PE 文件查看器。它非常整洁,但我对第一行有疑问:

#include "stdafx.h"
#include "Windows.h"
#include <iostream>

int main(int argc, char* argv[]) {
    const int MAX_FILEPATH = 255;
    char fileName[MAX_FILEPATH] = {0};
    memcpy_s(&fileName, MAX_FILEPATH, argv[1], MAX_FILEPATH);
    ...
}

如您所见,作者将 MAX_FILEPATH 定义为 255,但我不能这样做,因为我将给出的输入参数可能比这更大。

我决定使用 malloc 进行动态内存分配,这样我就可以拥有一个自动调整大小的数组(确切的参数长度),并且还可以为我保存 'memcpy_s' 函数:

#include <stdio.h>

#include "Windows.h"

#pragma warning (disable: 6011 6386 6387) // MSVC is giving me a headache.

int main(int argc, char *argv[]) {
    int length = strlen(argv[1]); // Yes, I only care for 1 input argument.
    char* path = malloc(length * sizeof(char));

    int i = 0;
    for (; i <= length; i++) {
        if (i < length) {
            path[i] = argv[1][i];
        }
        else {
            path[i] = '\0';
        }
    }
    ...
}

我知道“for cicle”在速度方面可能不是最佳选择,但我对此并不担心。相反,我很担心,因为一切似乎都很好,但是当我到达代码的第二部分(即 HANDLE 的创建)时,它总是返回错误。

HANDLE file = CreateFileA(path, GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

if (file == INVALID_HANDLE_VALUE) {
    printf_s("Nope."); // Always throwing nopes.
}

你知道我做错了什么吗?也许我试图混合不同的数据类型或函数的方式......?

非常感谢,提前。

顺便说一句,如果您对我的 C 编码风格有任何建议,或者如果某些东西不是真正的“C 标准”,请告诉我。

如果有人遇到同样的问题...

尝试以管理员身份运行您的程序...这完全与文件权限有关。

【问题讨论】:

  • char* path = malloc(length+1); 设为终止空字符。 `
  • 只使用argv[1] 有什么问题?例如。 char *path= argv[1];?或者干脆忘记path
  • 无论如何,按照正确的mallocstrcpy
  • 另外,sizeof(char) 在定义上总是一个。如果您使用 memcpy_s() 是因为 MSVC 说 memcpy() 已“弃用”,请注意您实际上被骗了。 memcpy() 没有也不会被任何人弃用 - 它是 standard C 并且不会消失。 MSVC 推动您使用 *_s 函数,这将是 C 标准附件 K 中的标准函数,但 Microsoft 的实现是非标准且不可移植的。见open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm#impementations
  • 感谢您的建议;我会修复它们并继续前进:)

标签: arrays c dynamic malloc


【解决方案1】:

除非有其他原因,否则无需复制argv[1],您可以直接使用它:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h> // use normal include guards

int main(int argc, char *argv[])
{
    if (argc < 2){ // if the argument is not there the program would have undefined behavior
        fprintf(stderr, "Usage: <prog> <filename>\n");
        return EXIT_FAILURE;
    }
    
    HANDLE file = CreateFileA(argv[1], GENERIC_ALL, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    //                        ^^^^^^^
    if (file == INVALID_HANDLE_VALUE) {
        printf_s("Nope."); // Always throwing nopes.
    }
    //...
}

在任何情况下,您都应该检查argv[1] 是否真的存在,否则您的程序将出现未定义的行为。

无论如何,如果你真的想复制,还有更好的选择,这里是其中之一:

#include <stdio.h>
#include <stdlib.h>
#include<string.h> // maybe needed for strdup
#include <Windows.h> // use normal include guards


int main(int argc, char *argv[]) {

    if(argc < 2){ // if the argument is not there the program would have undefined behavior
        fprintf(stderr, "Usage: <prog> <filename>\n");
        return EXIT_FAILURE;
    }
    // allocates memory for the new string and duplicates it
    char* path = _strdup(argv[1]); // MSVC can complain about POSIX strdup()
    //...
    // you'll need to free path
}

使用正确的数组大小,您仍然可以使用memcpystrcpy 库函数之一或其变体之一:

int length = strlen(argv[1]) + 1; // account for null byte
char *path = malloc(length); // sizeof char is always 1 byte
memcpy_s(path, length, argv[1], length); // path is already pointer, removing &

请注意,在您的代码中,filename 在作为参数传递时会衰减为指向其第一个元素的指针,因此您还应该删除 &amp;

或者干脆用指针:

char *path = argv[1];

虽然指针选项与直接使用argv[1]基本相同,如第一段代码所示。

如果还有与字符串无关的问题,GetLastError() 将帮助您查明问题所在。

【讨论】:

  • 我已经遵循了这两种方法(直接使用 argv[1] 和完整的 memcpy 函数),但它仍然抛出“nopes”,就像它无法读取文件一样(file == INVALID_HANDLE_VALUE) .. :(
  • @JulioVargas,这 3 个都应该工作,尝试打印出 GetLastError() 以查看确切的错误是什么,并将其发布在这里。如果您使用的是 Unicode 字符,则可能必须使用 LPTSTR argv[]TCHAR 而不是 char
  • GetLastError() == 5,所以这意味着这一切都与权限有关。我以管理员身份运行程序,一切正常。感谢您的建议!
  • @JulioVargas,确实如此,很高兴您解决了它,请注意,如果您认为它确实帮助您解决了问题,您可以accept the answer
猜你喜欢
  • 1970-01-01
  • 2015-07-12
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多