我目前正在学习C编程,并且经过一个简单的练习。
请参阅以下代码:
#include<stdio.h>
#include<stdlib.h>
char* nstars(int n);
int main(void)
{
int sn;
printf("Number of stars: ");
scanf("%d", &sn);
for(int i = 1; i <= sn; i++)
{
printf("\n%s", nstars(i));
}
return 0;
}
char* nstars(int n)
{
char* starstr = (char*) calloc(n, sizeof(char));
for(int nt=0; nt < n; nt++)
{
starstr[nt] = '*';
}
return starstr;
}
上面的代码将打印如下内容
sn=4
*
**
***
****
直到sn
高于23为止,代码才能正常工作。它将开始打印出奇怪的字符。
为什么会这样?我该如何解决?
答案 0 :(得分:2)
只需将n + 1
替换为calloc
:
还有:不要忘记free
!
char *
的末尾必须为'\ 0',因此您需要分配大小+ 1
#include<stdio.h>
#include<stdlib.h>
char* nstars(int n);
int main(void)
{
int sn;
printf("Number of stars: ");
scanf("%d", &sn);
for(int i = 1; i <= sn; i++)
{
char *str = nstars(i);
printf("\n%s", str);
free(str);
}
return 0;
}
char* nstars(int n)
{
char* starstr = (char*) calloc(n + 1, sizeof(char));
for(int nt=0; nt < n; nt++)
{
starstr[nt] = '*';
}
return starstr;
}
答案 1 :(得分:2)
您没有正确终止using
字符串-直到达到大小23为止,恰好发生是紧随{{1 }},直到现在为止看起来一切正常。
需要将n个字符的字符串存储在至少 个n + 1个元素的数组中,以说明终止符,因此您需要像这样调整starstr
调用:
starstr
一些注意事项-首先,从C89 1 开始,calloc
上的强制转换是不必要的,如果您使用的是C89编译器,则可以抑制有用的诊断 2 。其次,您可以在目标上使用char *starstr = calloc( n + 1, sizeof *starstr );
来获得正确的类型大小-表达式 calloc
的类型为sizeof
,因此*starstr
等效于char
。 sizeof *starstr
根据定义为1,因此严格来说,您可以将所有内容替换为文字sizeof (char)
,但是如果您决定使用sizeof (char)
这样的“宽”字符类型,则可以这样操作无需更改1
调用本身。
最后,按照编写的代码,此代码将发生相当多的内存泄漏-每次调用wchar_t
时都在分配一个新数组,但完成后并不会取消分配它。
坦率地说,您不必为每行分配一个新数组-以最终大小(为结束符分配为+1)分配一次一次,然后向其中添加一个新星号结束:
calloc
由于nstars
将分配的内存清零,因此在添加新的星号后,无需显式编写字符串终止符。如果您改用int main( void )
{
...
char *starstr = calloc( n + 1, sizeof *starstr );
/**
* ALWAYS check the result of a malloc, calloc, or realloc call.
*/
if ( !starstr )
{
fprintf( stderr, "Could not allocate memory for string - exiting\n" );
exit( 0 );
}
for ( int i = 0; i < n; i++ ) // Each time through the loop, add an
{ // asterisk to the end of starstr,
starstr[i] = '*'; // then print starstr.
printf( "%s\n", starstr );
}
free( starstr );
...
}
,则需要编写
calloc
malloc
,starstr[i] = '*';
starstr[i+1] = 0;
printf( "%s\n", starstr );
或malloc
需要弄脏你的手。
calloc
声明,因此,如果您忘记包含realloc
或在范围内没有int
的声明,则编译器会假定它返回stdlib.h
,如果您尝试将结果分配给指针,则会发出诊断信息。但是,如果将结果强制转换为指针,则编译器不会发出诊断信息,并且可能会遇到运行时错误。 C99和更高版本不再允许隐式calloc
声明,因此此特定问题不再是问题,但最好还是放弃。它使代码更易于阅读和维护。