我在一些脚本语言中相当能干,但我终于强迫自己学习C语言。我只是在玩一些基本的东西(现在是I/O)。我怎样才能分配堆内存,在分配的内存中存储一个字符串,然后吐出来呢?这就是我现在所拥有的,我怎样才能使它正常工作?Malloc和scanf
目前我收到奇怪的输出像'8'\'。
我在一些脚本语言中相当能干,但我终于强迫自己学习C语言。我只是在玩一些基本的东西(现在是I/O)。我怎样才能分配堆内存,在分配的内存中存储一个字符串,然后吐出来呢?这就是我现在所拥有的,我怎样才能使它正常工作?Malloc和scanf
目前我收到奇怪的输出像'8'\'。
char *toParseStr = (char*)malloc(10);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
首先,scanf
中的字符串指定了它将要接收的输入。为了在接受键盘输入之前显示一个字符串,使用printf
,如图所示。
其次,您不需要取消toParseStr
,因为它指向的大小为10的字符数组与您分配的malloc
。 如果您正在使用的功能,它会指向另一个内存位置,然后&toParseStr
是必需的。
例如,假设您想编写一个函数来分配内存。然后,您需要&toParseStr
,因为您正在更改指针变量的内容(这是内存中的一个地址---您可以通过打印其内容来查看自己的内容)。
void AllocateString(char ** ptr_string, const int n)
{
*ptr_string = (char*)malloc(n)
}
正如你可以看到,它接受char ** ptr_string
其内容,其存储一个指示字的存储器位置的指针,其将存储所分配的块的第一个字节的存储器地址(malloc
操作之后)的n
字节(现在它有一些垃圾内存地址,因为它是未初始化的)。
int main(int argc, char *argv[])
{
char *toParseStr;
const int n = 10;
printf("Garbage: %p\n",toParseStr);
AllocateString(&toParseStr,n);
printf("Address of the first element of a contiguous array of %d bytes: %p\n",n,toParseStr);
printf("Enter string here: ");
scanf("%s",toParseStr);
printf("%s",toParseStr);
free(toParseStr);
return 0;
}
第三,建议释放你分配的内存。即使这是你的整个程序,并且这个内存将在程序退出时被释放,但这仍然是一个好习惯。
即使在一个小程序中也可以释放+1。让我想起“小滴滴变成海洋”。 ;-) – 2010-07-21 03:54:01
您应该在打印提示符并调用scanf之间调用'fflush(stdout);'。大多数实现会做到这一点,让你彬彬有礼,但它不是强制性的。 – 2010-07-21 11:07:47
,因为它已经是一个指针
也呼吁free(toParseStr)
你不需要toParseStr
之前&
在scanf
事后
根据bball的系统,可能需要在该printf中放置一个“\ n”,以便正确显示事物。另外,10个字符是一个非常短的字符串。 – George 2010-07-21 02:35:56
虽然这是事实,但这并不是问题的根源(在这种情况下'&'是不必要的,但是无害的)。 – 2010-07-21 02:36:14
@Jerry它是无害的,因为格式说明符没有指定任何参数,但是一旦他修复它在你的答案中有一个%s就会导致段错误 – 2010-07-21 02:37:42
你需要给scanf
转换格式,因此它知道你想读一个字符串 - 现在,你只是显示在你分配的内存中发生的任何垃圾。而不是试图描述所有的问题,这里的一些代码,至少应该接近工作:
char *toParseStr = malloc(10);
printf("Enter a string: ");
scanf("%9s", toParseStr);
printf("\n%s\n", toParsestr);
/* Edit, added: */
free(toParseStr);
return 0;
编辑:在这种情况下,free
荷兰国际集团字符串不作任何真正的区别,但像其他人那样指出,它是是仍然是培养的好习惯。
+1正确使用'scanf'中的'%9s'。 – sarnold 2010-07-21 02:42:47
与某些人的看法相反,在执行读取操作之前,刷新'stdout'对于确保提示出现是不必要的,除非实现被正确地破坏了。对于那些真正关心的人,请参阅§7.19.3。如果可以确定*不*指向交互设备,'stdout'只能被完全缓冲。 – 2010-07-21 03:02:06
你错了。 'stdout'仍然可以**行缓冲**,这意味着直到打印换行符才会显示任何内容。 POSIX建议实现在读取时刷新stdout和其他这样的行缓冲流,但是扫描行缓冲流的打开文件列表(特别是使用线程和锁定)并且实现可能选择不执行所以出于很好的理由。据我所知,ISO C对缓冲语义几乎没有要求。所以你**应该**冲洗! – 2010-07-21 11:10:43
首先,使程序不能正常工作的错误:scanf(3)
采用格式字符串,就像printf(3)
一样,不是为用户打印的字符串。其次,您传递的是指针toParseStr
的地址,而不是指针toParseStr
。
我也从您的电话malloc(3)
删除不必要的演员。
你的程序仍然需要改进的地方是使用scanf(3)
的a
选项为你分配内存 - 这样一些小丑将十个字符放入你的字符串中并不会开始st on无关的内存。 (是的,C就会让别人几乎覆盖整个地址空间有了这个程序,书面巨安全漏洞。:)
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *toParseStr = malloc(10);
printf("Enter a short string: ");
scanf("%s",toParseStr);
printf("%s\n",toParseStr);
return 0;
}
'scanf'没有'a'选项。这是一个GNU扩展,它不仅是非标准的,而且还有** CONFLICTS **和ISO C('%a'是读取浮点数的说明符之一!)。应该绝对避免。 – 2010-07-21 11:15:29
谢谢;我不知道这个扩展与ISO C. – sarnold 2010-07-22 09:19:51
数据使用scanf()
(或fscanf()
你不控制)与标准“ %s“说明符是让你自己陷入缓冲区溢出困境的一种近乎确定的方式。
经典的例子是,我在你的程序中输入字符串“这个字符串超过10个字符”,混沌将随之而来,猫和狗将开始一起睡觉,裸露的奇点可能会出现并消耗地球(大多数人只是陈述“未定义的行为”,但我认为我的描述更好)。
我积极劝阻使用无法提供保护的功能。我会敦促你(特别是作为C的新手)使用fgets()
来读取你的输入,因为你可以更容易地控制缓冲区溢出,它比scanf()
更适合于简单的线路输入。
一旦你有了一条线,你就可以在其上调用sscanf()
到你心中的内容,顺便说一句,你不需要在这个特定的情况下做,因为你只是得到一个原始字符串。
我会用:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFSZ 10
int main(int argc, char *argv[]) {
char *toParseStr = malloc(BUFFSZ+2);
if (toParseStr == NULL) {
printf ("Could not allocate memory!\n");
return 1;
}
printf ("Enter a string: ");
if (fgets (toParseStr, BUFFSZ+2, stdin) == NULL) {
printf ("\nGot end of file!\n");
return 1;
}
printf("Your string was: %s",toParseStr);
if (toParseStr[strlen (toParseStr) - 1] != '\n') {
printf ("\nIn addition, your string was too long!\n");
}
free (toParseStr);
return 0;
}
+1有冲突,但我补充说,虽然'fgets'确实有优势,scanf和fscanf都有防止缓冲区溢出的措施。 – 2010-07-21 02:46:06
@Jerry虽然我很少看到人们用“%s”使用宽度说明符,但这是一个很好的观点:-)因为我的大多数控制台I/O代码都倾向于具有基于行的输入,所以%s不适合获得空白空间。但是,由于您的答案在这种情况下确实是正确的,所以您+1。 – paxdiablo 2010-07-21 03:02:12
另一个有趣的可能性是'scanf(“%9 [^ \ n]”,your_string);'''scanf'的面向行的字符串输入,无论值多少钱。 – 2010-07-21 03:10:23
你并不需要从'的malloc和''包括投的返回类型'在ISO C(3)。 –
sarnold
2010-07-21 02:34:34
值得指出的是,您应该在这里使用堆栈。 – dicroce 2010-07-21 02:36:27