[英]Defining strings using pointers Vs. char arrays in C
我对指向字符的指针如何工作感到困惑。 当我运行以下代码时,会发生什么?
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
main
中的第一行是在没有初始化的情况下定义指向 char 的指针。 scanf
应该将单词存储在某处并将地址提供给指针,对吗? 如果我输入一个大字符串,它会覆盖 memory 中的某些内容吗?
除了定义指向 char 的指针之外,以下代码的第一行会发生什么。 编译器是否设置了一些限制? 或者我不能超过指定的尺寸,对吗? 如果完成,我将遇到运行时错误,对吗? 这两种情况有什么区别?
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
指向其他类型的指针呢? 我可以继续使用偏移量写入以下位置吗?
scanf 应该将单词存储在某处并将地址提供给指针,对吗?
不,情况正好相反。 您定义scanf
存储值的地址。 由于您未能初始化指向某个有效地址的指针,您会导致未定义的行为,在最好的情况下可能会导致崩溃,或者在最坏的情况下似乎会起作用。
除了定义指向 char 的指针之外,以下代码的第一行会发生什么。
根本不涉及指针。 数组不是指针。 数组提供了存储其所有成员所需的所有 memory。 指针不会这样做。
function scanf
要求您将足够大的 memory 缓冲区的地址传递给它以存储字符串。 如果您不这样做,那么您将调用未定义的行为(即您的程序可能会崩溃)。
简单地传递一个野指针(即任意 memory 地址)是不够的。 相反,您必须保留您打算使用的 memory,例如通过声明一个数组或使用 function malloc
。
Using the %s
scanf
conversion format specifier by itself is not a good idea, because even if the allocated memory buffer has a size of 100 characters, if the user types more than 99 characters (100 including the terminating null character), then the function将越界写入数组,导致未定义的行为。 因此,您应该始终限制写入的字符数,在这种情况下通过写入%99s
而不是简单%s
。
此外,在使用scanf
的结果之前,您应该始终检查 function 的返回值,并且仅在 function 成功的情况下使用结果。
int main()
{
char word[100];
if ( scanf( "%99s", word ) == 1 )
printf( "%s\n", word );
}
如果我输入一个大字符串,它会覆盖 memory 中的某些内容吗?
它不必是“大”字符串。 即使将“小”字符串写入野指针也会导致未定义的行为,并且可能会覆盖重要的内容。
编译器是否设置了一些限制? 或者我不能超过指定的尺寸,对吗?
编译器不会阻止您越界写入数组,但是如果您允许这种情况发生,那么您的程序将具有未定义的行为(即您的程序可能会崩溃)。 因此,您可能不想让这种情况发生。
如果完成,我将遇到运行时错误,对吗?
如果幸运的话,是的,您的程序会立即崩溃,您将能够轻松识别并修复错误。 如果你不走运,那么不,你的程序不会崩溃,但会按预期工作,而且你不会在很长一段时间内注意到这个 bug,直到开发的很晚,有一天 bug 开始覆盖一些重要的东西在你的程序中。 在这种情况下,该错误可能很难诊断。
这是因为 C 不是内存安全语言。
但是,由于这类错误通常很难找到,因此有一些工具可以帮助检测这类错误,例如valgrind和AddressSanitizer 。
根据 C 标准中的转换说明符%s
的描述
如果不存在 l 长度修饰符,则相应的参数应是指向字符数组的初始元素的指针,该元素数组的大小足以接受序列和终止 null 字符,它将自动添加。
那就是你传递一个指针作为 function 的参数,它对应于格式%s
它应该指向将存储输入字符串的字符数组的第一个元素。 字符数组应足够大以容纳输入的字符串(包括附加的终止零字符'\0'
)
在第一个程序中
int main()
{
char* word;
scanf("%s",word);
printf("%s",word;
}
指针word
未初始化并且具有不确定的值。 所以这两个语句
scanf("%s",word);
printf("%s",word;
调用未定义的行为。
您需要提供指向字符数组的有效指针值。 例如
char s[100];
char *word = s;
或者您可以像动态分配 memory
char *word = malloc( 100 * sizeof( char ) );
在第二个节目
int main()
{
char word[100];
scanf("%s",word);
printf("%s",word;
}
用作参数的数组word
被隐式转换为指向其第一个元素的指针。 如果您将输入一个适合包含 100 个元素的数组的字符串,那么程序将正确运行。
但是,如果您将输入 100 个或更多字符而没有嵌入空格,那么程序将再次出现未定义的行为。
为了避免这种情况,您可以通过使用长度修饰符指定可以在数组word
中读取的字符串的最大长度,方法如下
scanf("%99s",word);
如果要输入可能包含嵌入空格的字符串,则应使用另一个转换说明符。 例如
scanf("%99[^\n]", word );
或者
scanf(" %99[^\n]", word );
下面是两个演示程序,它们显示了用于输入字符串的两个转换说明符之间的区别。
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99s", word );
puts( word );
return 0;
}
如果要输入字符串
Hello Mohammed Elbagoury
那么程序 output 将是
Hello
第二个程序
#include <stdio.h>
int main(void)
{
char word[100];
scanf( "%99[^\n]", word );
puts( word );
return 0;
}
如果再次进入
Hello Mohammed Elbagoury
那么程序 output 将是
Hello Mohammed Elbagoury
如果您将输入超过99
字符,则只有前99
字符将存储在附加了终止零字符'\0'
的数组中。
至于你这个问题
我可以继续使用偏移量写入以下位置吗?
然后您可以使用指针算法将数据存储在数组的任何 position 中。 例如
int a[10];
scanf( "%d", a + 5 );
在这种情况下,将在数组a[5]
的元素中写入一个数字。
上面的语句等价于
scanf( "%d", &a[5] );
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.