为什么添加 char 字符后不打印新字符串?

问题描述 投票:0回答:3

我打算用 C 语言编写一些 leetspeak 代码,但是,我不断收到如下错误:

error: incompatible integer to pointer conversion returning 'char' from a function with result type 'string' (aka 'char *') [-werror,-wint-conversion]

或者只是我的最新代码没有返回任何值。

#include <cs50.h>
#include <stdio.h>

string replace(string no_vowels);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Error message\n");
        return 1;
    }
    else
    {
        printf("This is your message: %s\n", replace(argv[1]));
    }
}

string replace(string no_vowels)
{
    int i = 0;
    while (no_vowels[i] != '\0')
    {
        i++;
    }

    string subs = "6310";
    string new_string = "";

    for (int l = 0; l < i; l++)
    {
        if (no_vowels[l] == 'a')
        {
            new_string += subs[0];
        }
        else if (no_vowels[l] == 'e')
        {
            new_string += subs[1];
        }
        else if (no_vowels[l] == 'i')
        {
            new_string += subs[2];
        }
        else if (no_vowels[l] == 'o')
        {
            new_string += subs[3];
        }
        new_string += no_vowels[l];
    }
    return new_string;
}

我尝试使用应该直接替换字母的数字创建数组,尝试添加或减去值,考虑到 ASCII 表中的每个字符字符,并在 StackOverflow 上查找现有线程

PS:我正在尝试使用已导入的库进行此练习。

c char cs50 c-strings function-definition
3个回答
3
投票

您无法像在 javascript 中那样使用

+=
连接 C 中的字符串。对于此赋值,您可以就地修改参数字符串并返回原始指针。

这是修改后的版本:

string replace(string no_vowels)
{
    string subs = "6310";

    for (int i = 0; no_vowels[i] != '\0'; i++)
    {
        if (no_vowels[i] == 'a')
        {
            no_vowels[i] = subs[0];
        }
        else if (no_vowels[i] == 'e')
        {
            no_vowels[i] = subs[1];
        }
        else if (no_vowels[i] == 'i')
        {
            no_vowels[i] = subs[2];
        }
        else if (no_vowels[i] == 'o')
        {
            no_vowels[i] = subs[3];
        }
    }
    return no_vowels;
}

另请注意,CS50 课程中

string
typedef 的目的是隐藏实现并避免 C 新手受到指针冲击。这就像小孩子的后轮,你应该很快将它们拆下并学习真正的技能。

这是具有实际类型的修改版本:

#include <cs50.h>
#include <stdio.h>

char *replace(char *str);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Invalid argument count\n");
        return 1;
    } else {
        printf("This is your message: %s\n", replace(argv[1]));
        return 0;
    }
}

// replace vowels in place in the argument string
char *replace(char *str) {
    const char *subs = "6310";

    for (int i = 0; str[i] != '\0'; i++) {
        if (str[i] == 'a') {
            str[i] = subs[0];
        } else
        if (str[i] == 'e') {
            str[i] = subs[1];
        } else
        if (str[i] == 'i') {
            str[i] = subs[2];
        } else
        if (str[i] == 'o') {
            str[i] = subs[3];
        }
    }
    return str;
}

1
投票

我将根据您的代码假设您并不打算修改输入字符串,而是返回一个包含修改内容的新字符串。

C 字符串的级别比 Python 等字符串低。 C 字符串是一个字符数组,然后是字符串长度加上 1 作为空终止符 (

'\0'
)。

您需要为

new_string
创建这样一个数组。幸运的是,您知道长度,因为您的程序不会更改原始字符串的长度。您可以分配一个新字符串,按照替换逻辑复制到其中,然后返回新字符串。

char * replace(const char *str) {
    size_t len = strlen(str);
    char new_string[len + 1];

    for (size_t i = 0; i < len + 1; i++) {
        // assign new_string[i] from str[i] as appropriate
    }

    // Assign the null terminator.
    new_string[len] = '\0';

    return new_string;
} 

除了 C 还有一个问题。您返回的指针可能仍指向该数组,也可能不指向该数组。通过从函数返回指向局部变量的指针,您可以调用未定义的行为。

您需要动态分配新字符串,以便内存“比函数调用更长寿”。在使用该内存之前,您还需要检查

malloc
的返回,以防它不起作用并且没有为您分配您期望的内存。

char * replace(const char *str) {
    size_t len = strlen(str);
    char *new_string = malloc(len + 1);
    if (new_string == NULL) return NULL;

    for (size_t i = 0; i < len + 1; i++) {
        // assign new_string[i] from str[i] as appropriate
    }

    // Assign the null terminator.
    new_string[len] = '\0';

    return new_string;
} 

0
投票

您的函数定义无效。

在这一行

string new_string = "";

您声明了一个指向字符串文字的指针。任何更改字符串文字的尝试都会导致未定义的行为。

来自 C 标准(6.4.5 字符串文字)

7 未指定这些数组是否不同,只要它们的 元素具有适当的值。 如果程序尝试 修改这样的数组,行为是未定义的。

在这样的声明中

new_string += subs[0];

使用了指针算术来改变指针

new_string
本身。因此,指针具有无效值,该值不指向函数中声明的有效对象。如果假设这样的语句被正确重写,那么这个语句

new_string += no_vowels[l];

在任何情况下都是错误的,因为从逻辑上讲,您试图覆盖 if-else 语句中已经更新的字符。

这个 while 循环

while (no_vowels[i] != '\0')
{
    i++;
}

是多余的。字符串以终止零字符

'\0'
结束。因此,您可以使用这个事实创建遍历字符串的循环条件。在任何情况下,变量
i
l
都应具有无符号类型
size_t
,而不是有符号类型
int

据我所知,字母

'u'
也是一个元音。然而你忽略了它和大写元音。

无需创建新字符串。根据 C 标准,您可以更改指向 ponters 的程序参数

argv

来自C标准(5.1.2.2.1程序启动)

  1. — 参数 argc 和 argv 以及 argv 数组指向的字符串应可由程序修改,并保留它们的值 程序启动和程序终止之间最后存储的值。

该函数可以如下所示

string replace( string no_vowels )
{
    string subs = "6310";

    for ( char *p = no_vowels; *p != '\0'; ++p )
    {
        if ( *p == 'a' )
        {
            *p = subs[0];
        }
        else if ( *p == 'e' )
        {
            *p = subs[1];
        }
        else if ( *p == 'i' )
        {
            *p = subs[2];
        }
        else if ( *p == 'o' )
        {
            *p = subs[3];
        }
    }

    return no_vowels;
}
© www.soinside.com 2019 - 2024. All rights reserved.