为什么当参数是指针时函数不起作用?

Why does the the function not work when the parameter is a pointer?

提问人:mbed 提问时间:7/28/2021 更新时间:7/28/2021 访问量:97

问:

#include "stdio.h"
#include "stdlib.h"


typedef enum lightSwitch {
        OFF = 0,
        ON
}lightSwitch;

void setLight(lightSwitch setting){
        if(setting == 1){
                printf("(v)\n =\n");
        }
}
int main(void){

  char *p = malloc(sizeof(lightSwitch));
  printf("'ON' or 'OFF'?\n");
  scanf("%s", p);
  setLight(*p);

}

我不完全确定这段代码有什么问题。当用户输入“OFF”时,灯泡应该保持隐藏状态,但如果用户输入“ON”,则应该显示灯泡。

C 函数 指针 枚举 malloc

评论

6赞 bolov 7/28/2021
枚举不是字符串
1赞 Weather Vane 7/28/2021
顺便说一句,你是说?您没有使用您定义的值。if(setting == ON)enum
1赞 stark 7/28/2021
*p是来自用户的字符串的第一个字符,可能是“O”
1赞 LEF 7/28/2021
枚举只是一个“掩码”或“映射”或任何你想用于整数的词,在这种情况下,与 没有太大区别。你的代码似乎暗示你相信枚举将字符串映射到一个值,就好像字符串“OFF”解析为 0,如果你认为你对枚举的理解是错误的。#define OFF 0#define ON 1

答:

1赞 Wahalez 7/28/2021 #1

你试图向 malloc 请求内存,并传递枚举的大小,你应该向它传递你希望字符串的 sizeof(char) * 字符数(请注意,你需要留一个字节来终止字符串)。

其次,您正在尝试比较 char* 和整数。

你应该做的是这样的:

if(strcmp(p,"ON") == 0) 
 setLight(ON); //use the enum attribute
else
 setLight(OFF);

检查输入字符串,然后将所需的相应枚举值传递给 setLight 函数。

评论

0赞 Adrian Mole 7/28/2021
像这样的代码永远不会起作用。()如何等于字符串()?if(*p == "ON")char*p"ON"
4赞 Ruks 7/28/2021 #2

使用 时,需要注意两点:char *p = malloc(sizeof(lightSwitch));

  1. 确保在你不再需要它的时候。(虽然在这种情况下不是必需的,因为程序会在终止后自动为您释放它,但您仍然应该这样做,因为它被认为是良好的做法。free(p)
  2. sizeof (lightSwitch)本质上只是编写依赖于平台的,因此字符串的大小可能在不同的平台上有所不同,并且可能会导致未定义的行为,这是永远不可取的。sizeof (int)
/* The below two lines shouldn't be used unless you have put both 'stdio.h'
   and 'stdlib.h' inside your program's source directory, which isn't really a sane idea */
// #include "stdio.h"
// #include "stdlib.h"

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

typedef enum lightSwitch {
    OFF,
    ON
} lightSwitch;

void setLight(lightSwitch setting) {
    if(setting == ON)
        printf("(v)\n =\n");
}

int main(void) {
    // It suffices to simply use an array instead of a dynamically allocated pointer in this context
    char p[4] = {0};

    printf("'ON' or 'OFF'?\n");
    scanf("%3s", p);

    // strcmp(a, b) essentially compares the equality of two strings passed to it and returns 0 if they are equal
    setLight(strcmp(p, "ON") == 0 ? ON : OFF);
}
0赞 user253751 7/28/2021 #3

枚举不是字符串。OFF 只是 0 的另一种写法。而 ON 只是 1 的另一种写法。它们与字符串“ON”或“OFF”无关。编译程序时,编译器不会将名称“ON”或“OFF”放入程序中,因此程序不知道它们的名称。

因此,考虑到这一点,您的程序正在分配一些内存,将字符串读取到该内存中(即假设用户键入 ON,然后字节 0 变为“O”,字节 1 变为“N”,字节 3 变为 0),然后检查第一个字节是否等于 1,但事实并非如此,因为“O”的 ASCII 代码是 79。

0赞 John Bode 7/28/2021 #4

枚举常量与字符串是完全不同的动物,它们彼此之间完全没有联系。您不能将变量或常量的名称作为字符串输入并能够访问相应的值 - C 无法以这种方式工作。ON"ON"

您将不得不找到一种方法来手动映射字符串和相应的枚举值(或放弃使用枚举而只使用字符串)。"ON""OFF"

若要读取字符串,需要一个足够大的缓冲区来保存字符串的所有字符以及字符串终止符。在这种情况下,绝对没有必要使用动态内存1 - 您只需要分配一个固定长度的数组:char

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

#define MAX_CHARACTERS 3 // length of "OFF"

int main(void){

  char buf[MAX_CHARACTERS+1] = {0}; // +1 to allow for the string terminator

  printf("'ON' or 'OFF'?\n");

  /**
   * We're going to use fgets instead of scanf - it's easier to
   * protect against buffer overflow.  
   */
  if ( fgets( buf, sizeof buf, stdin ) ) 
  {                                      
    /**
     * First, make sure the input string is all upper case - that way 
     * we don't have to worry about comparing against "on", "On", "oN",
     * etc.
     */
    for ( char *p = buf; *p != 0; p++ )
      *p = toupper( *p );

    /**
     * Create a variable of type lightSwitch - this is what we'll
     * pass to setLight.  Default value is OFF
     */
    lightSwitch setting = OFF; 

    if ( strcmp( buf, "ON" ) == 0 )
      setting = ON;

    setLight( setting );        
  }
  else
  {
    // handle input error here
  }
}

如所写,这只有在用户键入时才会启用灯光;对于任何其他输入,指示灯将熄灭。如果你不想创建一个单独的变量,我们也可以写它:"ON"

if ( strcmp( buf, "ON" ) )
  setLight( ON );
else
  setLight( OFF );

这将做同样的事情。


  1. sizeof (lightSwitch)返回对象的大小(可能少至 2 个字节),而不是保存字符串所需的字符数 或 ;在分配空间来存储字符串时,需要为 N 个字符加上字符串终止符分配空间。更好的选择是用作 的参数,但在这种情况下,您不需要使用动态内存。lightSwitch"ON""OFF"strlen( "OFF" ) + 1malloc