C通过引用传递,单维和多维

时间:2013-11-14 07:54:22

标签: c arrays string pointers pass-by-reference

好的,我知道这可能会被标记为副本,但我到处搜索都无法解决这个问题,所以请耐心等待。

首先我要说这是一个家庭作业,所以我不能改变功能参数类型。

此外,我不允许使用 任何 库(嗯,在进行更改的函数内)。

第1部分

<小时/> 首先,我将如何做到这一点:

void changeMe(char* s, int size) {
   //Change s to be "Hello, World!"
}

int main(void) {
   char* c;
   changeMe(c, 13);
   printf("%s", c); //Print out "Hello, World!"
}

(作业不会要求“Hello,World!”位,但我不需要逻辑帮助,只需更改传递的变量。)

我已经查看了所有内容,大多数答案最终都是这样的here,其中说我需要参数char** schar*& s才能更改它。

我唯一的选择是假设在传递之前已经分配了足够的内存吗?例如:

void changeMe(char* s, int size) {
   int i;
   for (i = 0; i < size - 1; i++) s[i] = 'a';
   s[size - 1] = '\0';
}

int main(void) {
   char* c = (char*) malloc(10 * sizeof(char)) ;
   changeMe(c, 10);
   printf("%s", c); //Prints out "aaaaaaaaa"
}

这样可以正常使用,但从malloc(...)声明中删除c则不然。

malloc(...)放在changeMe(...)函数内部,但只有changeMe在范围内才能持续。

有没有办法改变我的char* c而不假设它在传递给函数之前已经分配了足够的内存?

第2部分


这几乎与上面的内容完全相同,所以我会在这里解释一下。

功能:

void split(char* s, char** sub, int max, char sep) {
   //Split string s by sep char, store all substrings found into sub
   //sub will have at most max substrings in it.
}

我并没有要求帮助编写char* s char c查找和分割char** sub的逻辑。我能做到。我的问题与上述问题基本相同。如何为void split(char* s, char** sub, int max, char sep) { //-->(Needed) Make sub able to hold max strings. //(Not Needed) Logic for splitting s up by sep, creating a substring. //-->(Needed) Making sub[i] have memory to hold current substring. } int main(void) { char* s = "Some String To Use"; char** subs; split(s, subs, 10, ' '); //subs should look like this: //{"Some", "String", "To", "Use"} } 分配内存,以便它可以适应其中的所有子字符串(当然,更改传递的变量)。

例如:

subs

我在实际工作中不需要帮助,我很困惑如何将split(...)传递给subs并让它分配适当的内存并更改char** s。< / p>


如果你通过我的问题做到这一点,谢谢你的阅读。

而且,在所有的“你试过谷歌”评论进来之前,是的。这是我到目前为止所看到的一些内容:

(编辑:谢谢,haccks,为我添加超链接。)

同样,如果我自己写这个,我会改变参数(例如char* s而不是strcpy),并使用像{{1}}等好的有用函数,但在这种情况下,我无法做到这一点。任何帮助/意见将非常感谢,非常感谢你们提前!

4 个答案:

答案 0 :(得分:1)

第1部分

size参数的重点是函数changeMe()知道缓冲区的大小。您不需要假设大小,通常,这样的函数将按如下方式使用:

int main()
{
    int size;
    char* c;

    // some code to calculate the required size of the buffer in bytes
    size = calculateRequiredSize();

    // allocate the buffer
    c = ( char* )malloc( size );

    changeMe( c, size );
}

但是,在回答您的问题时,在函数changeMe()中,如果没有假设已经分配了size字节的内存缓冲区,则无法更改缓冲区中存储的数据。< / p>

第2部分

这里有相同的逻辑,尽管它是分为两部分(双关语)。

只需修改您的示例,即可执行以下操作:

void split(char* s, char** sub, int max, char sep) {

    char*   pCurrent;   // pointer to the beginning of the current substring inside the original string.
    int     lenCurrent; // length of the current substring

    // Making sub[i] have memory to hold current substring.
    int i;
    for ( i = 0; i < max; ++i )
    {
        //(Not Needed) Logic for splitting s up by sep, creating a substring.
        // OK -> I leave it to you.

        sub[i] = (char *)malloc( lenCurrent + 1 );  // use length of the current substring + an extra space for the terminating NULL character

        // I will leave it to you to copy the substring to sub[i]
    }
}

int main(void) {
    char* s = "Some String To Use";
    int max = 10; // Decide the value of max out here.
    char** subs = (char**)malloc( max * sizeof( char* ) );
    // Make subs able to hold max strings.
    split(s, subs, max, ' ');
    //subs should look like this:
    //{"Some", "String", "To", "Use"}
}

答案 1 :(得分:0)

祝你好作业!至少你是诚实的,承认你在这里做作业...... :)

关注第2部分:

Sub实际上是一个char * - (char *sub[max])的数组。

所以你需要查看s,找到拆分的位置以及拆分部分的大小。之后,在sub []数组中分配所需的大小。通过这种方式,您将准确分配所需的金额。

另一种解决方案: 如果您不允许使用malloc(),则可以更改* s字符串。翻过来,将sep的每次出现更改为'\0'。然后将正确的sub[i]指针指向字符串的开头。这实际上就是strsep()的工作原理。

Demonstartion:

我们假设s"Hello-World-This-Is-Homework"。 然后将sub[0]设置为指向s[0],这是第一部分的开头。结束s直到下一个'-'。将其更改为'\0'。然后将s[1]指向"World"的开头,并将下一个'-'更改为'\0'等等。

关注第1部分:

在你告诉我们在第2部分你收到一个已经分配的数组之后,我假设在第1部分中,数组也已经被分配了。所以你实际上有char s[size]。所以看起来你的解决方案是正确的 - 如果用户传递了错误的元素大小,这就是他的错。你无法验证它。

答案 2 :(得分:0)

当您修改作为参数传递给函数的数组(指针)时,您也会在调用者中修改它的内容。这是因为C通过复制参数来工作,但在这种情况下,它复制指针,而不是它指向的值。因此,您需要修改指针在函数中指向的值,而不必以特殊方式传递指针。但是,请注意,为了能够访问和修改内存,必须在调用者函数中分配它。这就是为什么你不能删除malloc。

答案 3 :(得分:0)

第1部分

如果您的函数原型changeMe(char * s,int size)无法更改 那么你唯一的选择就是为函数提供一个很大的缓冲区 足以容纳你的新字符串,

void changeMe( char* s, int size )
{
  if ( s != NULL && s > 0 )
  {
    char* p = strncpy( s, "Hello, World", size-1 ); // assuming size includes \0
    if ( p != NULL )
    {
      p[size - 1] = '\0'; // make sure it is 0 terminated.
    }
  }
}

你需要“char ** s”作为改变参数的原因 大小是char * s表示地址被传递给 按值的功能,即原始地址的副本 类似于如果你已经通过说一个int:

void foo(int n) // n is a copy of the original value
{
  n = 1; // modifying the copy
}

在foo之外,n的值不会改变,但如果你写了

void foo(int* n) // n is now pointing to the original value
{
  *n = 1; // changing what n points to i.e. the original value
}  

当谈到字符串时,它与原则相同 更多层次的间接

void foo(char* s)
{
  s = "hello"; // just temporarily changes what the copy s points to, not the original
}

void foo(char** s)
{
  *s = malloc(10); // changes what the original s points to
}

第2部分

提示:查看realloc(),该函数作为malloc运行,但扩展了内存块 动态