使用命令行为 C 中的结构赋值

问题描述

我正在尝试使用命令行设置具有许多值的结构。我在 MS 商店的 Ubuntu 18.04ls 终端中执行程序时提供了这些属性。但是我遇到了一个问题,因为我无法访问终端上写的那些属性

这是我的代码

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

#define TAMANIOMAXIMO 20

struct persona {
  char nombre[TAMANIOMAXIMO];
  int edad;
  float ingresos;
}

main (int argc,char *argv[]) {
  printf("%d\n",argc);
  
  char nameProf[] = "";
  stpcpy(nameProf,argv[1]);
  int edadProf = atoi(argv[2]);
  float ingresosProf = atof(argv[3]);
  struct persona profesor = {nameProf,edadProf,ingresosProf};
  
  struct persona alumno;
  
  strcpy(alumno.nombre,"Juan");
  alumno.edad=19;
  alumno.ingresos=11.777;
  
  printf("Los ingresos conjuntos de alumnno y profesor son %f\n",alumno.ingresos+profesor.ingresos);
  exit(1);
} 

执行结果如下:

./a.out james 10 12
-691680792
Los ingresos conjuntos de alumnno y profesor son 11.777000

我不知道为什么参数 argc(存储 argv 的元素数量)有这个长度。我尝试删除在 main 函数之前的 struct 'persona' 的定义,一切都是正确的。 argv[1]、argv[2] 和 argv[3] 的内容不是在命令行中作为参数给出的,argv[0] 不存储“./a.out”,因为它应该存储。

解决方法

因为你在struct后面忘记了;,所以编译器认为struct是main的返回类型。

您还应该有 int main 而不是只有 main

修复项目中问题的良好开端是打开编译器的警告(例如 -Wall-Werror)。

,

对于 struct persona 定义的右大括号,将 } 更改为 }; 以结束声明。

main (int argc,char *argv[]) 更改为 int main(int argc,char *argv[])。缺少分号和 int 导致 main 的错误声明可能会干扰向其传递参数,导致 argc 参数被错误获取。

char nameProf[] = "";中,数组大小取自初始化器"",所以它只有一个元素,一个终止空字符。因为它只有一个元素,所以其中的 stpcpy 会破坏内存,导致您的程序行为异常。您可以将定义更改为 char nameProf[TAMANIOMAXIMO] = "";。然而,这个数组不是必需的,所以只需删除它和它后面的 stpcpy

struct persona profesor = {nameProf,edadProf,ingresosProf}; 中,您不能使用另一个命名数组 (nombre) 初始化数组(nameProf 成员)。 (您可以使用字符串文字初始化 char 的数组,但这不是您在这里想要的。)暂时将 nameProf 命名为 {0} 以将数组初始化为零。然后,在此行之后,使用 strcpy(profesor.nombre,argv[1]); 将名称复制到数组成员中。 (这就是不需要 nameProf 的原因;您只需将命令行参数直接复制到结构成员中即可。)

在编译器中打开警告并注意它们。

,

如果我们编译您的程序时不做任何更改,但将 -Wall -Werror 传递给 gcc,我们会得到:

$ gcc -Wall -Werror -o scratch main.c
main.c:7:1: error: return type of 'main' is not 'int' [-Werror,-Wmain-return-type]
struct persona {
^
main.c:7:1: note: change return type to 'int'
struct persona {
^~~~~~~~~~~~~~
int
main.c:20:30: error: incompatible pointer to integer conversion initializing 'char' with an expression of type 'char [1]' [-Werror,-Wint-conversion]
  struct persona profesor = {nameProf,ingresosProf};
                             ^~~~~~~~
main.c:20:30: error: suggest braces around initialization of subobject [-Werror,-Wmissing-braces]
  struct persona profesor = {nameProf,ingresosProf};
                             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                             {                               }
3 errors generated.

因此,只需将这些标志传递给 GCC,您就可以获得修复程序所需的所有信息。

,

您的程序存在多个问题,导致其行为未定义。我不清楚为什么这种未定义的行为会特别表现为打印出意外的值,但这完全在可能的 UB 范围内。

问题包括

  1. 正如@Gnoom 在他们的回答中指出的那样,您在 struct persona 的声明后省略了一个分号,另外还省略了 main 的返回类型。结果是返回 struct persona 的函数的语法正确声明,但需要 main 返回 int

  2. 此声明:

    char nameProf[] = "";
    

    charName 声明为一个数组,长度刚好足以容纳一个空字符串,包括终止符——也就是说,只有一个字节。这不足以容纳您稍后尝试读入的名称,因此您超出了该缓冲区。

  3. 这个声明中的初始化...

    struct persona profesor = {nameProf,ingresosProf};
    

    ... 没有你期望的效果。正如您不能通过 = 运算符将一个数组分配给另一个数组一样,您也不能通过将数组变量的标识符放在与该成员对应的初始化程序中来初始化数组或成员数组的元素。

您的编译器应该至少警告您其中的一些,并且您应该养成阅读编译器警告并确保您理解它们告诉您的内容的习惯。在您获得更多经验之前,您应该假设每个警告都表示一个需要解决的问题,以免您的程序无法正常运行。