好的,我知道这可能会被标记为副本,但我到处搜索都无法解决这个问题,所以请耐心等待。
首先我要说这是一个家庭作业,所以我不能改变功能参数类型。
此外,我不允许使用 任何 库(嗯,在进行更改的函数内)。
<小时/> 首先,我将如何做到这一点:
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** s
或char*& 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
而不假设它在传递给函数之前已经分配了足够的内存?
这几乎与上面的内容完全相同,所以我会在这里解释一下。
功能:
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}}等好的有用函数,但在这种情况下,我无法做到这一点。任何帮助/意见将非常感谢,非常感谢你们提前!
答案 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运行,但扩展了内存块 动态