繁体   English   中英

使用指针定义字符串 Vs。 C 中的字符 arrays

[英]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 不是内存安全语言。

但是,由于这类错误通常很难找到,因此有一些工具可以帮助检测这类错误,例如valgrindAddressSanitizer

根据 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM