【问题标题】:How can I copy the contents of argv[] into a c style string?如何将 argv[] 的内容复制到 c 样式字符串中?
【发布时间】:2023-04-01 11:01:02
【问题描述】:

我正在尝试编写一个程序,该程序在运行时接受多个参数以将文本附加到文件中。

程序在运行时产生分段错误。这是代码:

int main(int argc, char* argv[])
{
    //error checking
    if (argc < 1 || argc > 4) {
        cout << "Usage: -c(optional - clear file contents) <Filename>, message to write"    << endl;
        exit(EXIT_FAILURE);
    }

    char* filename[64];
    char* message[256];

    //set variables to command arguments depending if -c option is specificed
    if (argc == 4) {
        strcpy(*filename, argv[2]);
        strcpy(*message, argv[3]);
    } else {
        strcpy(*filename, argv[1]);
        strcpy(*message, argv[2]);
    }

    int fd; //file descriptor 

    fd = open(*filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist    then create one
    fchmod(fd, 00000);

    return 0;
}

我还是个初学者,在理解 c 字符串时遇到了很大的困难。 char* 和 char[] 和 char* [] 有什么区别?

更新:

代码仍然抛出分段错误,这是我修改后的代码:

using std::cout;
using std::endl;

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

//error checking
if (argc < 1 || argc > 4) {
cout << "Usage: -c(optional - clear file contents) <Filename>, message to write"      << endl;
 exit(EXIT_FAILURE);
 }

char filename[64];
char message[256];

 //set variables to command arguments depending if -c option is specificed
 if (argc == 4)
{
strncpy(filename, argv[2], 64);
strncpy(message, argv[3], 256);
}
 else
 {
strncpy(filename, argv[1], 64);
strncpy(message, argv[2], 256);
 }

 int fd; //file descriptor 

 fd = open(filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist then create one
 fchmod(fd, 00000);


 return 0;

 }

【问题讨论】:

  • 您通过提供完整的程序尝试获得积分;有很多东西要学,但你已经很接近了。

标签: c++ string unix segmentation-fault


【解决方案1】:

char* filename[64] 创建一个包含 64 个指针的数组。您打算为 64 个字符的字符串创建空间 - 这将是 char filename[64]。因为您只为指针分配空间,而从未使指针指向任何内存,所以会出现段错误。

解决方法:使用char filename[64];

这会为您的字符串创建一个 64 字节的块;值filename 指向此块的开头,可用于复制操作

strcpy(filename, argv[2]);

我强烈建议使用“复制不超过 n 个字符”功能 - 这可以防止非常长的参数导致缓冲区溢出。因此

strncpy(filename, argv[2], 64);

会更安全。更好

strncpy(filename, argv[2], 63);
filename[63] = '\0';

这保证了复制的字符串是空终止的。

message 也有同样的问题。我认为您不需要重复代码...

如果您需要更多信息,请告诉我。

更新
今天我了解到strlcpy 的存在——见this answer。即使原始字符串比分配的空间长,它也会考虑包含NUL 字符串终止符。有关更完整的讨论,请参阅this,包括此功能并非在所有编译器上都可用的原因(如果您尝试编写可移植代码,这当然是一个主要缺点)。

【讨论】:

  • 很好的答案!我明白。 filename 的输出是什么?这有点令人困惑,因为 strcpy 状态的语法 (char dest, char* src) 所以我假设这就是你声明 c 字符串的方式。
  • “文件名的输出”?字符串(filename 指针指向的内存块将包含argv[2] 指向的字符,直到并包括终止'\0'strcpy 的语法是strcpy(char *dest, const char *source);,其中不完全是你刚刚写的...例如见cplusplus.com/reference/cstring/strcpy
  • 至于“你如何声明 C 字符串”——一个 C 字符串被一个 pointer 引用到一个 内存块(你需要确保已分配,并且足够大),'\0' 字符结尾(您还需要空间)。有不同的技术来分配空间; filename[64] 是一个(注意 - 这对于 63 个字符的字符串 _plus 终止 '\0' 足够大),或者 const char myString = "hello world"; 如果您不打算更改它(内存已分配给您) ,或者您以char myString; 开头,然后以myString = malloc(100); 开头以创建空间。
  • @Floris - 很棒的解释。每个'C'老师都应该这样教:)
  • @Purisima - 非常感谢。 20 多年来,我一直在与指针等作斗争——我知道在硬币下降之前它们是多么令人眼花缭乱。只是想帮助路上的一位乘客编码......
【解决方案2】:

由于您已将其标记为 C++(但尚未有人提及):

argv 已经是一个 C 风格的数组,所以不需要复制到另一个(除非你只是想浪费空间)。如果您真的想将其复制到某个东西中,std::string 对象将是更好的方法:

int main(int argc, char* argv[])
{
    // assuming your conditional checks are already done here ...
    std::string filename = argv[1];
    std::string message = argv[2];
    // do something
    return 0;
}

【讨论】:

  • +1 表示“您实际上并不需要复制argv 以使您的程序正常工作!
【解决方案3】:

您的变量filenamemessagechar 指针 数组,而不是C 样式的字符串(应该是空终止的char 数组)。所以你需要将它们的类型声明为:

char filename[64];
char message[256];

并使用strcpy 作为:

strcpy(filename, argv[2]);
strcpy(message, argv[3]);

open 的调用类似:

fd = open(filename, O_RDWR | O_CREAT, 00000);

【讨论】:

  • 所以基本上我有一个充满指向 NULL 的指针的数组?
  • @Revoo 你有一大堆未初始化 char 指针。
【解决方案4】:

>>> 我还是个初学者,在理解 c 字符串时遇到了很大的困难。 char 和 char[] 和 char* [] 有什么区别?*

指针在你第一次遇到时很难理解。

  • char 是内存中的单个字节
  • char* 是指向内存的指针(可以是单个字节或字符数组)
  • char[]是一个字符数组,可以指向char*
  • char*[] 是一个指向 char 的指针数组

当你有一个变量文件名时,*filename 取消引用该变量,这意味着它不是指针,而是指向的东西。

  • *filename 是 char 类型,不是 strcpy 的有效参数,这是您的 segfault 发生的地方
  • *message 是 char 类型,不是 strcpy 的有效参数,这是您的下一个段错误发生的地方
  • open(*filename 又是一个字符,它不是 open 的有效参数

您的程序大部分是正确的。问题是您不清楚如何使用指针。这是您的代码,稍作修改即可工作。我注释掉了损坏的部分,以便您可以将损坏的部分与已修复的部分进行比较。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int
main(int argc, char* argv[])
{
    //char* filename[64];
    //char* message[256];
    char filename[64]; //declare filename, point it at char[64]
    char message[256]; //declare message, point it at char[256]
    int fd; //file descriptor 

    printf("argc %d\n",argc);
    //error checking
    if ( (argc < 1) || (argc > 4) )
    {
        //cout << "Usage: -c(optional - clear file contents) <Filename>, message to write"    << endl;
printf("Usage: -c(optional - clear file contents) <Filename>, message to write\n");
        exit(EXIT_FAILURE);
    }

    int argi=1;
    if( !strcmp(argv[argi],"-c") ) { argi++; } //clear
    //set variables to command arguments depending if -c option is specificed
    if (argc == 4)
    {
        //strcpy(*filename, argv[argi++]);
        //strcpy(*message, argv[argi++]);
        strcpy(filename, argv[argi++]);
        strcpy(message, argv[argi++]);
    }
    else
    {
        //strcpy(*filename, argv[argi++]);
        //strcpy(*message, argv[argi++]);
        strcpy(filename, argv[argi++]);
        strcpy(message, argv[argi++]);
    }

    //fd = open(*filename, O_RDWR | O_CREAT, 00000); //open file if it doesn't exist    then create one
    if( !(fd = open(filename, O_RDWR | O_CREAT, 00000)) ) //open file if it doesn't exist    then create one
    {
        //always check for failure to open
        //and emit error if file open fails
        exit(EXIT_FAILURE);
    }
    //fchmod(fd, 00000);
    write(fd,message,strlen(message));

    return 0;
}

【讨论】:

  • 很好的解释。
  • 当没有给出参数时。固定。
【解决方案5】:

我还是个初学者,在理解 c 字符串时遇到了很大的困难。 char* 和 char[] 和 char* [] 有什么区别?

对您的明确问题的简短回答是 char*char[] 都可以用作 C 字符串。另一方面,char* []C-strings 的数组。

【讨论】:

    猜你喜欢
    • 2021-06-17
    • 2010-10-28
    • 2010-10-27
    • 2014-06-11
    • 1970-01-01
    • 2019-11-18
    • 2021-09-13
    相关资源
    最近更新 更多