【问题标题】:C invalid operands to binary + (have ‘char *’ and ‘char *’)?二进制+的C无效操作数(有'char *'和'char *')?
【发布时间】:2021-08-16 17:35:22
【问题描述】:

在 C 中我有:

filedata->string_table + (X)->sh_name

现在我想在它旁边添加以下字符串:“new”

我试过了:

filedata->string_table + (X)->sh_name + "new"

但这不会编译,我得到:

readelf.c:6807:83: error: invalid operands to binary + (have ‘char *’ and ‘char *’)
  filedata->string_table + (X)->sh_name : filedata->string_table + (X)->sh_name+"new")
                                          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~      ^

如何解决这个问题?

【问题讨论】:

  • 如果你想连接字符串,有一些函数可以实现(例如strcat)。 + 是算术运算符
  • 编译器错误是不言自明的。请学习你最喜欢的 C 书籍中关于 C 字符串的章节。
  • 这里涉及的成员有哪些类型?第一个 sn-p 看起来很可疑。

标签: arrays c string macros char


【解决方案1】:

使用正确的方式连接字符串。

如果要将结果添加到现有缓冲区,请使用strcat() 连接字符串。

char buffer[1024000]; /* enough size */
strcpy(buffer, filedata->string_table + (X)->sh_name);
strcat(buffer, "new");

您也可以使用snprintf() 将连接的结果放入缓冲区。

char buffer[1024000]; /* enough size */
snprintf(buffer, sizeof(buffer), "%s%s",
    filedata->string_table + (X)->sh_name, "new");

要将结果打印到标准输出,请使用两个%s 格式说明符连续打印两个字符串。

printf("%s%s",
    filedata->string_table + (X)->sh_name, "new");

如果字符串"new"是固定的,你也可以这样做:

printf("%snew",
    filedata->string_table + (X)->sh_name);

【讨论】:

  • 字符缓冲区[1024000]; ???为什么不strlen(str1) + strlen(str2) + 1
  • 请注意the default stack size on Microsoft Windows is 1 MB,因此char buffer[1024000]; 可能会导致该平台上的堆栈溢出。
  • @0___________ 因为有些编译器卡在 1989 年的 ANSI C 上,无法处理 VLA (*cough* MSVC *cough*)
  • @AndrewHenle 然后malloc 是你的朋友。 BTW 使用对本地对象的引用是 UB,所以这个想法是双重错误的。
【解决方案2】:

您不能使用运算符+ 连接stringschar。使用strncat()snprintf()

【讨论】:

  • 对不起,这些函数会影响字符串,但我想要一个新的
  • 你可以使用strcpy创建一个新的字符串。
  • 谢谢!我改写了我的答案。
【解决方案3】:

(X)->sh_name+"new" + 在 C 中不连接字符串。它试图添加指向无效指针的指针。

你需要使用函数strcatstrncat

对不起,这些函数会影响字符串,但我想要一个新的 -

就这么简单:

char *strcatAlloc(const char * restrict s1, const char * restrict s2)
{
    size_t s1len;
    char *newstring;

    if(s1 && s2)
    {
        s1len = strlen(s1);
        newstring = malloc(s1len + strlen(s2) + 1);
        if(newstring)
        {
            strcpy(newstring, s1);
            strcpy(newstring + s1len, s2);
        }
    }
    return newstring;
}

int main(void)
{
    // you should check if the function fails. Omitted for the example clarity
    printf("`%s`\n", strcatAlloc("hello ", "world"));
    printf("`%s`\n", strcatAlloc("", "world"));
    printf("`%s`\n", strcatAlloc("hello ", ""));
    printf("`%s`\n", strcatAlloc("", ""));

    //you should free allocated space
}

或您可以传递缓冲区的版本(如果该缓冲区为 NULL,它将分配内存)

char *strcatAlloc(const char * restrict s1, const char * restrict s2, char *buff)
{
    size_t s1len;

    if(s1 && s2)
    {
        s1len = strlen(s1);
        if(!buff) buff = malloc(s1len + strlen(s2) + 1);
        if(buff)
        {
            strcpy(buff, s1);
            strcpy(buff + s1len, s2);
        }
    }
    return buff;
}

int main(void)
{

    char s[100];
    // you should check if the function fails. Omitted for the example
     printf("`%s`\n", strcatAlloc("hello ", "world", NULL));
    printf("`%s`\n", strcatAlloc("", "world", NULL));
    printf("`%s`\n", strcatAlloc("hello ", "", s));  //you can pass your own large enough buffer 
    printf("`%s`\n", strcatAlloc("", "", NULL));

    //you should free allocaated space
}

【讨论】:

  • 我假设,sh_name 是一个整数。否则,第一个 sn-p 已经无法编译。该代码似乎来自readelf.c
  • @Gerhardh 即使不是它也会是相同的错误,只在同一行重复两次:) 答案是一样的
  • 对不起,这些函数会影响字符串,但我想要一个新的
  • @daniel 您必须注意在不再需要新内存区域后释放它。
  • @Gerhardh 它在我的 cmets 代码中
【解决方案4】:

请记住,C 没有实际的字符串类型 - 字符串存储在 char 的数组中,并且 C 没有为数组类型定义 += 运算符。

您可以使用strcatstrncat 将字符串附加到字符缓冲区:

char foo[] = "This is ";
char bar[] = "a test";
char target[ sizeof foo + sizeof bar ];

strcpy( target, foo ); // copies contents of foo to target buffer
strcat( target, bar ); // appends contents of bar to target buffer

目标缓冲区必须足够大以容纳包括终止符在内的最终字符串。在此示例中,我们采用了 foobar 的大小(不是长度!),它们分别为 9 和 7(包括字符串终止符)。请注意,如果它们被声明为,这将不起作用

char *foo = "This is ";
char *bar = "a test";

因为sizeof foo 只会给我们指针对象的大小,而不是它指向的字符串的大小。在这种情况下,您必须在运行时使用strlen 获取大小。如果您使用的是支持 VLA(C99 或更高版本)的版本,您可以这样做

char *foo = "This is ";
char *bar = "a test";

char target[ strlen( foo ) + strlen( bar ) + 1];

如果没有,您必须动态分配缓冲区:

char *target = malloc( strlen( foo ) + strlen( bar ) + 1 );

完成后您必须记住free


如果你有字符串和非字符串类型的混合,你可以使用sprintf

char *name = "blah";
int number = 42;

sprintf( target, "%s-%d", name, number ); // writes "blah-42" to target buffer

同样,目标缓冲区必须足够大以存储结果字符串和终止符。

【讨论】:

  • "that supports VLAs (C99 or later)" -- 请注意,兼容 C11 的编译器不需要支持 VLA。 VLA 已降级为 C11 中的可选功能。
  • @AndreasWenzel:这两点都是正确的。至于使用大小参数,在我自己的代码中,我通常会在到达sprintf 语句本身之前对缓冲区大小进行所有健全性检查,因此我倾向于不使用大小参数。
  • 在您回答之前,我删除了我的第二条评论(关于在格式字符串中使用 %.*s% 而不是 %s 的评论),因为您是对的,无论如何都必须事先执行完整性检查,当使用strcat。因此,我关于在使用函数 sprintf 时推荐额外的尺寸保护措施的评论似乎并不合适。这就是我撤回评论的原因。
猜你喜欢
  • 1970-01-01
  • 2015-11-21
  • 2014-09-30
  • 1970-01-01
  • 2021-08-20
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
相关资源
最近更新 更多