【问题标题】:Argv doesnt work with char pointer on terminalArgv 不适用于终端上的 char 指针
【发布时间】:2022-01-21 08:56:12
【问题描述】:

我想编写一个程序,当我在终端上写prog.exe -u word 时,会将word 转换为大写,否则跳过该过程。但是当我编译下面的代码时,屏幕上什么也没有,我无法弄清楚为什么会发生错误。

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

char u[] = "-u";

void upper(const char *src, char *dest);

int main(int argc, char const *argv[]) {
    if (argc < 3) {
        printf("Input at least 3 argument!\n");
    } else
    if (!(strcmp(argv[1], u))) {
        char *output;
        upper(argv[2], output);
        printf("%s\n", output);
    } else {
        printf("No option\n");
    }
    return 0;
}

void upper(const char *src, char *dest) {
    while (*src) {
        if (*src >= 97 && *src <= 122) {
            *dest = *src - 32;
        } else {
            *dest = *src;
        }
        src++;
        dest++;
    }
    *dest = *src;
}

【问题讨论】:

  • char * output; upper(argv[2],output); 你觉得这里发生了什么?
  • 永远不要使用像 97 或 122 这样的幻数。改用*src &gt;= 'a' &amp;&amp; *src &lt;= 'z'

标签: c initialization undefined-behavior c-strings argv


【解决方案1】:

程序具有未定义的行为,因为您尝试将转换后的字符串存储到未初始化的指针output

请注意,使用诸如9712232 之类的硬编码常量既令人困惑,也无法移植到非ASCII 环境中。您应该使用来自&lt;ctype.h&gt; 的宏和函数以提高可读性和可移植性。

您可以通过这种方式简单地修改参数字符串:

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

void upper(char *str);

int main(int argc, char *argv[]) {
    if (argc < 3) {
        printf("Input at least 3 arguments!\n");
    } else
    if (!(strcmp(argv[1], "-u"))) {
        printf("%s\n", upper(argv[2]));
    } else {
        printf("No option\n");
    }
    return 0;
}

char *upper(char *str) {
    for (char *p = str; *p; p++) {
        *p = toupper((unsigned char)*p);
    }
    return str;
}

【讨论】:

    【解决方案2】:

    指针output 声明为

    char * output;
    

    未初始化且具有不确定的值。

    所以在函数upper 中使用它会调用未定义的行为。

    你应该使用一个足够大的字符数组而不是指针来存储传递给函数的字符串。

    如果编译器支持变长数组,那么你可以写

    char output[ strlen( argv[2] ) + 1 ];
    

    还有这个 if 语句

    else if( strcmp(argv[1],u) == 0 ){
    

    会比这个 if 语句更易读

    else if(!(strcmp(argv[1],u))){
    

    在函数中,至少在 if 语句中使用字符符号 'a''z' 而不是幻数 97122 会更好

    if(*src >= 97 && *src <= 122){
      *dest = *src - 32;
    }
    

    虽然使用标头&lt;ctype.h&gt;中声明的标准函数islowertoupper会更好。

    函数可以通过以下方式声明和定义

    #include <ctype.h>
    
    //...
    
    char * upper( char *dest, const char *src )
    {
        char *result = dest;
    
        do
        {
            if ( islower( ( unsigned char )*src ) )
            {
                *dest++ = toupper( ( unsigned char )*src );
            }
            else
            {
                *dest++ = *src;
            }
        } while ( *src++ );
    
        return result;
    }
    

    【讨论】:

      【解决方案3】:
      void upper(const char *src, char *dest) {
        char *tmp = dest; // hold pointer
        while(*src) {
          *dest = (*src >= 97 && *src <= 122) ? *src - 32 : src;
          ++src; ++dest;
        }
        *dest = '\0'; // end of string
        dest = tmp;
      } 
      

      【讨论】:

      • 这有什么变化?
      • 您需要支持您的 dest 变量的指针,该指针指向您的 dest 开始的地址。在您的情况下发生的事情是您返回 dest 变量结束的地址,因此您丢失了实际数据
      • @yemo 该函数处理其局部变量。所以传递给函数的原始指针不会被改变。
      • @VladfromMoscow 是的,你是对的,我的错。我没有考虑“外部”变量的地址和本地操作。谢谢。
      猜你喜欢
      • 2018-04-05
      • 2015-04-08
      • 2012-05-09
      • 1970-01-01
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 2013-06-19
      • 2012-05-27
      相关资源
      最近更新 更多