我在c学校的任务中挣扎了好几天。任务是编写一个接受字符串数组及其长度的函数,然后检查数组中最短字符串的长度,最后收集长度等于传递数组中最短长度的字符串。给出主要函数并期望写好,它只传递字符串数组,然后调用函数循环返回的数组以打印它的内容。 main()使用了一个tmp指针,对我来说也不清楚,为什么这是必要的,如果有人可以对那个有所了解,也会受到赞赏。
所以我的代码看起来像这样:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **foo(char **t, int size){
int i;
int current_length;
int shortest_length = strlen(t[0]);
int num_of_shortest = 0;
//define shortest string length
for(i = 0; i < size; i++)
{
current_length = strlen(t[i]);
if(shortest_length > current_length)
shortest_length = current_length;
}
//define the number of the shortest strings
for(i = 0; i < size; i++)
{
current_length = strlen(t[i]);
if(shortest_length == current_length)
num_of_shortest++;
}
//define an array, to hold the shortest things in order of appearance in the passed array of strings
static char **array_of_shortests;
array_of_shortests = malloc(sizeof(char)*num_of_shortest);
for(i = 0; i < size; i++)
{
current_length = strlen(t[i]);
//allocate memory for the string stored in the array of shortest strings
array_of_shortests[i] = (char *)malloc(strlen(t[i])+1);
//fill up the array of the shortest strings
if(shortest_length == current_length)
{
array_of_shortests[i] = t[i];
}
}
return array_of_shortests;
}
int main()
{
char *t[] = {"apple", "pineapple", "orange", "apple", "banana", "grape"};
char **result = foo(t, sizeof(t) / sizeof(char *));
char **tmp;
for (tmp = result; *tmp; ++tmp)
printf("%s\n", *tmp);
free(result);
return 0;
}
它编译得很好,但在运行时会产生以下错误:
[root@berlin tmp]# gcc -o practice_shortest_strings practice_shortest_strings.c
[root@berlin tmp]# ./practice_shortest_strings
apple
apple
grape
*** Error in `./practice_shortest_strings': free(): invalid next size (fast): 0x0000000000809010 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7c503)[0x7f88d95e0503]
./practice_shortest_strings[0x40081d]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f88d9585b35]
./practice_shortest_strings[0x400549]
======= Memory map: ========
00400000-00401000 r-xp 00000000 fd:00 100943188 /tmp/practice_shortest_strings
00600000-00601000 r--p 00000000 fd:00 100943188 /tmp/practice_shortest_strings
00601000-00602000 rw-p 00001000 fd:00 100943188 /tmp/practice_shortest_strings
00809000-0082a000 rw-p 00000000 00:00 0 [heap]
7f88d4000000-7f88d4021000 rw-p 00000000 00:00 0
7f88d4021000-7f88d8000000 ---p 00000000 00:00 0
7f88d934e000-7f88d9363000 r-xp 00000000 fd:00 69263259 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f88d9363000-7f88d9562000 ---p 00015000 fd:00 69263259 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f88d9562000-7f88d9563000 r--p 00014000 fd:00 69263259 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f88d9563000-7f88d9564000 rw-p 00015000 fd:00 69263259 /usr/lib64/libgcc_s-4.8.5-20150702.so.1
7f88d9564000-7f88d971a000 r-xp 00000000 fd:00 67658381 /usr/lib64/libc-2.17.so
7f88d971a000-7f88d991a000 ---p 001b6000 fd:00 67658381 /usr/lib64/libc-2.17.so
7f88d991a000-7f88d991e000 r--p 001b6000 fd:00 67658381 /usr/lib64/libc-2.17.so
7f88d991e000-7f88d9920000 rw-p 001ba000 fd:00 67658381 /usr/lib64/libc-2.17.so
7f88d9920000-7f88d9925000 rw-p 00000000 00:00 0
7f88d9925000-7f88d9945000 r-xp 00000000 fd:00 67149962 /usr/lib64/ld-2.17.so
7f88d9b37000-7f88d9b3a000 rw-p 00000000 00:00 0
7f88d9b41000-7f88d9b44000 rw-p 00000000 00:00 0
7f88d9b44000-7f88d9b45000 r--p 0001f000 fd:00 67149962 /usr/lib64/ld-2.17.so
7f88d9b45000-7f88d9b46000 rw-p 00020000 fd:00 67149962 /usr/lib64/ld-2.17.so
7f88d9b46000-7f88d9b47000 rw-p 00000000 00:00 0
7ffdfbf81000-7ffdfbfa2000 rw-p 00000000 00:00 0 [stack]
7ffdfbfbb000-7ffdfbfbd000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
请在这里帮助我,我没有想法......坦克帮助很多!
答案 0 :(得分:0)
发布的代码包含几个问题。有关详细信息,请参阅问题的评论。
以下建议代码:
foo()
很糟糕,它没有说明函数的作用。如果有选择,我更喜欢:selectShortestStrings()
calloc()
而不是malloc()
,因此内存已预先初始化为所有NULL size_t
而不是int
来避免隐含的转化&#39; main()
功能
虽然签名应该是:int main( void )
通过有意义的子函数名称,代码块分离和类似修改,可读性将大大增强lowerCamelCase
以便于变量名称和一致性的可读性。foo()
放在main()
之后,以便读取代码向下进行而不是向上跳回。i
的范围本地化在使用它的每个代码块中。`lowerCamelCase:
的定义lowerCamelCase(CamelCase的一部分)是一种命名约定,其中名称由多个单词组成,这些单词作为单个单词连接在一起,并且新单词中的每个单词的第一个字母(第一个单词除外)大写形成名称的词。
现在建议的代码:
#include <stdio.h> // printf()
#include <stdlib.h> // calloc(), free(), exit(), EXIT_FAILURE
#include <string.h> // strlen()
// prototypes
char **foo( char **, size_t );
int main()
{
char *t[] = {"apple", "pineapple", "orange", "apple", "banana", "grape"};
char **result = foo(t, sizeof(t) / sizeof(char *));
char **tmp;
for (tmp = result; *tmp; ++tmp)
printf("%s\n", *tmp);
free(result);
return 0;
}
char **foo( char **stringPtrs, size_t size )
{
// using 'size_t' because 'strlen()' returns a 'size_t'
size_t currentLength;
size_t shortestaLength = strlen(stringPtrs[0]);
size_t numOfShortest = 0;
//define shortest string length
for( size_t i = 0; i < size; i++)
{
currentLength = strlen( stringPtrs[i]);
if(shortestaLength > currentLength)
shortestaLength = currentLength;
}
//define the number of the shortest strings
for( size_t i = 0; i < size; i++)
{
currentLength = strlen(stringPtrs[i]);
if(shortestaLength == currentLength)
numOfShortest++;
}
// define an array, to hold the pointer to the shortest things
// in order of appearance in the passed array of strings
char **shortestPtrs = NULL;
// note printing loop in main() checks for NULL pointer
// so, just incase all the entries are the same length
// allocate room for extra entry and set all to NULL
shortestPtrs = calloc(numOfShortest+1, sizeof( char* ));
if( !shortestPtrs )
{
perror( "calloc failed" );
exit( EXIT_FAILURE );
}
// implied else, calloc successful
// cannot have NULL pointer in middle of array
// so indexing of output has to be separate from index of input
size_t shortestIndex = 0;
for( size_t i = 0; i < size; i++)
{
currentLength = strlen(stringPtrs[i]);
//fill up the array of the shortest strings
if(shortestaLength == currentLength)
{
shortestPtrs[ shortestIndex ] = stringPtrs[i];
shortestIndex++;
}
}
return shortestPtrs;
} // end function: foo
结果输出为:
apple
apple
grape
答案 1 :(得分:0)
您的代码中存在两个主要问题。首先,您为array_of_shortests
的分配分配num_of_shortest
(字符)而不是num_of_shortest
(指针) - 导致您的体系结构的分配不足sizeof (a pointer)
({ x86_64上的{1}}。在验证分配并将最后一个 sentinel 指针设置为8
时,您可以按如下方式更正它:
NULL
您的下一个错误是(1)/* define an array of pointer to holding the address to the shortest
* strings in order of appearance in the passed array of strings
*/
if (!(array_of_shortests =
malloc (sizeof *array_of_shortests * (num_of_shortest + 1))))
return NULL;
array_of_shortests[num_of_shortest] = NULL; /* set sentinel NULL */
中每个字符串的不必要的存储分配,(2)索引array_of_shortests
的不正确,以及(3)无法释放您分配的内存对于每个字符串,在调用array_of_shortests[i]
以释放free (result)
中的指针之前。
由于main
中的字符串已经有足够的存储空间作为array_of_shortests
引用的字符串文字,所以你关心的只是指向最短文字的地址并存储t
中的指针地址(您不需要再分配内存来再次复制/存储字符串文字)。你只需要分配array_of_shortests
,你已经在上面做了num_of_shortest + 1
为你的 sentinel NULL 提供空间,用于你在{{1}中使用的迭代方案然后,将每个最短的地址分配给例如+1
:
main
然后回到array_of_shortests[ndx++]
,你可以像你一样迭代,打印和int i,
ndx = 0,
...
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
/* you allocated 'pointers' no need to allocate storage for each,
* the pointers can hold the address of the shortest in 't'.
* NOTE: you cannot use array_of_shortests[i]
*/
if (current_length == shortest_length)
array_of_shortests[ndx++] = t[i];
}
指针。将各个部分放在一起,你可以做到:
main
示例使用/输出
free
内存使用/错误检查
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **foo (char **t, int size) {
/* valdiate parameters - minimally */
if (!t || !*t || size < 1) {
fprintf (stderr, "foo() error: invalid paramater.\n");
return NULL;
}
char **array_of_shortests = NULL;
int i,
ndx = 0,
current_length,
shortest_length = strlen (t[0]),
num_of_shortest = 0;
/* define shortest string length */
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
if (current_length < shortest_length)
shortest_length = current_length;
}
/* define the number of the shortest strings */
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
if (shortest_length == current_length)
num_of_shortest++;
}
/* define an array of pointer to holding the address to the shortest
* strings in order of appearance in the passed array of strings
*/
if (!(array_of_shortests =
malloc (sizeof *array_of_shortests * (num_of_shortest + 1))))
return NULL;
array_of_shortests[num_of_shortest] = NULL; /* set sentinel NULL */
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
/* you allocated 'pointers' no need to allocate storage for each,
* the pointers can hold the address of the shortest in 't'.
* NOTE: you cannot use array_of_shortests[i]
*/
if (current_length == shortest_length)
array_of_shortests[ndx++] = t[i];
}
return array_of_shortests;
}
int main (void) {
char *t[] = { "apple", "pineapple", "orange",
"apple", "banana", "grape" },
**result = foo (t, sizeof t / sizeof *t),
**tmp = result;
if (!result) {
fprintf (stderr, "foo() error: result is NULL.\n");
return 1;
}
while (*tmp)
printf ("%s\n", *tmp++);
free (result); /* free array of pointers */
return 0;
}
将指针传递给 $ ./bin/shorteststrs
apple
apple
grape
而不是使用Sentinel
虽然向$ valgrind ./bin/shorteststrs
==23647== Memcheck, a memory error detector
==23647== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==23647== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==23647== Command: ./bin/shorteststrs
==23647==
apple
apple
grape
==23647==
==23647== HEAP SUMMARY:
==23647== in use at exit: 0 bytes in 0 blocks
==23647== total heap usage: 1 allocs, 1 frees, 32 bytes allocated
==23647==
==23647== All heap blocks were freed -- no leaks are possible
==23647==
==23647== For counts of detected and suppressed errors, rerun with: -v
==23647== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
添加额外指针并将其设置为num_of_shortest
没有任何问题,但您的另一个选择是在array_of_shortests
中声明NULL
并简单地通过,并在num_of_shortest
内更新指针。这提供了一种在main
中提供foo
的方法。 E.g。
num_of_shortest
示例使用/输出
main
内存使用/错误检查
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **foo (char **t, int size, int *num_of_shortest) {
/* valdiate parameters - minimally */
if (!t || !*t || size < 1 || !num_of_shortest) {
fprintf (stderr, "foo() error: invalid paramater.\n");
return NULL;
}
char **array_of_shortests = NULL;
int i,
ndx = 0,
current_length,
shortest_length = strlen (t[0]);
*num_of_shortest = 0;
/* define shortest string length */
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
if (current_length < shortest_length)
shortest_length = current_length;
}
/* define the number of the shortest strings */
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
if (shortest_length == current_length)
(*num_of_shortest)++;
}
/* define an array of pointer to holding the address to the shortest
* strings in order of appearance in the passed array of strings
*/
if (!(array_of_shortests =
malloc (sizeof *array_of_shortests * *num_of_shortest)))
return NULL;
for (i = 0; i < size; i++) {
current_length = strlen (t[i]);
/* you allocated 'pointers' no need to allocate storage for each,
* the pointers can hold the address of the shortest in 't'.
* NOTE: you cannot use array_of_shortests[i]
*/
if (current_length == shortest_length)
array_of_shortests[ndx++] = t[i];
}
return array_of_shortests;
}
int main (void) {
int i, n = 0; /* pass address of n to foo */
char *t[] = { "apple", "pineapple", "orange",
"apple", "banana", "grape" },
**result = foo (t, sizeof t / sizeof *t, &n);
if (!result) {
fprintf (stderr, "foo() error: result is NULL.\n");
return 1;
}
for (i = 0; i < n; i++)
printf ("%s\n", result[i]);
free (result); /* free array of pointers */
return 0;
}
注意:在分配中保存“指针”(这是无关紧要的,但值得注意)。
仔细看看,如果您有其他问题,请告诉我。