C - 自己的str_join函数不起作用

时间:2017-08-30 10:29:24

标签: c pointers parameter-passing function-call

我想在C中创建一个简单的str_join函数(以学习更多关于指针和数组的内容),它实际上将两个字符串连接在一起。

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

int str_size(char *str);
void str_join(char *str1, char *str2);

int main(int argc, char **argv)
{
    char *part1 = "Hello ";
    char *part2 = "World!";
    str_join(part1, part2);
    printf("%s\n", part1);
    return 0;
}

int str_size(char *str)
{
    char c;
    for(int i = 0;; i++)
    {
        c = str[i];
        if(c == '\0')
            return i + 1;
    }
}

void str_join(char *str1, char *str2)
{
    int str_size_1 = str_size(str1) - 1; //Last char is '\0', don't need them 2 times
    int str_size_2 = str_size(str2);
    char str3[str_size_1 + str_size_2];
    int i;

    for(i = 0; i < str_size_1; i++)
        str3[i] = str1[i];

    for(i = 0; i < str_size_2; i++)
        str3[i + str_size_1] = str2[i];

    str1 = (char *)str3;
}

看起来很简单(也许太简单了)。 我将输出除外:

Hello World

但看起来像是:

Hello 

我使用以下命令编译程序:

gcc main.c -o main

然后跑了:

./main

我没有看到我的失败,有人能指出我的错误吗? 谢谢你帮助我!

4 个答案:

答案 0 :(得分:1)

在C中,函数参数按值传递。对函数内部的任何参数所做的任何更改都不会反映给调用者(实际参数)。

因此,在您的情况下,str1 = (char *)str3;并不符合您的想法。

那说,等等,停! str3是VLA,生命周期是块范围。您不可能返回第一个元素的地址,并期望在访问内存位置的范围之外有效。您需要以超出其范围的方式分配内存。您必须

  • 使用具有static存储的数组(不能与VLA结合使用)
  • 使用内存分配器功能

答案 1 :(得分:0)

您没有返回您认为从函数返回的指针。

str1 = (char *)str3;

您似乎认为这会更改str1,以便它指向(正确)连接的字符串str3,但此更改在函数外部不可见。

您可以(至少)以两种方式解决此问题:

1)与malloc

分配
char *str3 = malloc(str_size_1 + str_size_2);

然后从函数返回此指针(而不是void)

或2)

将指针传递给指向函数的指针,就像这个

一样
void str_join(char **str1, char *str2)

然后

*str1 = str3;

答案 2 :(得分:0)

您希望实现的目标是在函数调用方法的引用调用方法的帮助下完成的。但是在您的代码中,str_join是一个按函数调用的函数。当您更改str1的值时,它仅针对函数的范围进行更改。因为,当您从str_join范围退出时,str1的值再次更改为较早的值,因为您传递给函数的内容不是str1的地址,而是str1值的副本。你应该试试这个:

void str_join(char **str1, char **str2) 

// though the str2 need not to be passed by reference you can leave it as it is now

str1

替换函数内的*str1

然后您可以在主要功能中将其称为:str_join(&str1, &str2)

&符号表示您传递的地址为str1str2

答案 3 :(得分:0)

我确信有很多方法可以实现此处所需的内容。在C语言中,一种合理的惯用方法是创建一个新的动态分配字符串,其大小足以容纳原始字符串,并将其返回给调用者。

var filteredRecords = originalRecords.GroupBy(x => new 
{
    ContractReference = x.Fields[nameof(FieldName.CRFS.ContractReference)],
    ActionDate        = x.Fields[nameof(FieldName.CRFS.ActionDate)],
    Amount            = x.Fields[nameof(FieldName.CRFS.Amount)],
    CycleDate         = x.Fields[nameof(FieldName.CRFS.CycleDate)]
});

调用者必须在结果上调用free()。通常的做法是假设任何返回“char *”的函数返回必须释放的东西,而返回“const char *”的函数返回不需要释放的东西。但是,C标准库中的许多基本的,长期存在的函数都不遵循此约定。