为什么带有星号和没有星号的指针变量在printf中表现不同?

时间:2017-05-06 15:11:31

标签: c arrays pointers

我是编程新手,有些部分让我在学习指针时感到困惑。

代码1:

int main()
{
    char string[]="hello";

    char *my_pointer=string;

    printf("first character is %c", *my_pointer);
    return 0;
}

输出:第一个字符是h

代码2:

int main()
{    
    char array_of_words[]="one\0two\0three";

    char *my_pointer=array_of_words;

    printf("%s \n",my_pointer);

    return 0;
}

输出:一个

的问题:

我在这里混淆,第一个代码中的printf函数部分使用星号符号表示指向内部指针(my_pointer),这是变量字符串的地址,引用指向内存的数组的指针字符串数组“hello”中第一个单词的地址。我的理解是真的吗?

当我在printf中更改%c时(“第一个字符是%c”,* my_pointer); 到%s,程序崩溃了。我想知道为什么我不能使用%s 如果我不在printf中的my_pointer中使用星号(“第一个字符是%c”,my_pointer),那会有什么不同;

在第二个代码中,my_pointer变量在{printf(“%s \ n”,my_pointer);}中没有使用星号(*)。在这段代码中my_pointer是指array_of_words变量的地址还是my_pointer里面的内容?以及为什么输出是'一'而不是'o'?

4 个答案:

答案 0 :(得分:5)

C字符串,数组和指针可能非常混乱。让我们来看看每个人是什么。

指针指的是内存中的地址。你似乎对它们有些熟悉。可以把它想象成一个储物柜钥匙 - 它告诉你在内存中你可以存储数据的地方。

当您声明一个数组时,编译器会设置一个内存区域来存储它。您调用该数组的变量可以被视为指向该数据开头的指针。例如,* string是字符串的第一个元素。

现在让我们将其应用到你的程序中。

两个程序都创建一个字符串并将my_pointer设置为字符串开头的内存地址。 my_pointer=string表示"将变量string的内容(将其衰减到字符串开头的地址)复制到my_pointer。"

在程序1中,将*my_pointer读作" my_pointer指向的内存地址的内容。"由于my_pointer指向字符串的第一个元素,即字符h

为什么在替换%s时它会崩溃?因为printf需要一个指向字符串的指针,所以它可以遍历整个数组。由于C是按值复制的,因此给它第一个元素的值是没有意义的,因为它无法获得任何其他元素。结果,printf尝试将字符作为内存地址读取,该地址失败。一个好的编译器可能会看到并给你一个警告。

现在程序2. my_pointer引用内存中字符串的地址,而不是变量array_of_words的地址。输出为one因为printf打印所有内容直到第一个空字符(\0)。由于第一个空值就在one之后,它会打印one,然后点击空值并停止。

答案 1 :(得分:2)

当您声明char string[]="Hello"时,您声明了一个字符数组。

string指向数组的第一个元素。 *被称为解除引用运算符。

假设ptr是一个整数指针。 *ptr将为您提供指针ptr指向的内存位置的内容。在声明时,您必须将其声明为int *ptr,以便编译器知道ptr是指针变量(因此在那里是星号)。

执行printf("first character is %c", *my_pointer);时,函数需要一个与%c对应的字符。声明char *stringchar string[]大致(非完全)等效。 my_pointer是一个字符类型指针。 *my_pointer解除引用my_pointer。换句话说,*my_pointer为您提供my_pointer的内容,即字符串中的第一个字符。

但是%s期望一个字符串(一个字符数组,基本上是一个char指针)作为printf中的对应参数。 *my_pointer是一个角色。 my_pointer可以视为字符串。此外,print会将参数视为字符串并打印who; e,直到\0

my_pointer=array_of_wordsarray_of_words的值“分配”给my_pointer

array_of_words[]是一个数组,因此array_of_words的值基本上是数组第一个元素的内存地址(注意缺少[])。实际上my_pointer现在指向数组的第一个元素。

希望这能解释它。

答案 2 :(得分:2)

  

第一个代码中的printf函数部分使用星号符号表示   指向内部指针(my_pointer)的内容是什么   变量字符串,用于引用数组的指针字符串   指向数组“hello”中第一个字的内存地址。是我的   理解是真的吗?

Ans *my_pointer中的printf表示当前指针my_pointer指向的内存地址所代表的值。即'h'。指针不知道array;它只知道一个内存地址。

你知道,声明和定义期间的*意味着两件不同的事情。前者表示变量类型是指向char类型值的指针,后者表示ValueOf operator(*)

  

当我在printf中更改%c时(“第一个字符是%c”,* my_pointer);至   %s,程序崩溃。我想知道为什么我不能使用%s

Ans :这是因为当printf看到%s占位符时,它希望提供的对象是一个指针,以便它可以从第一个char迭代到空值(\0)。但在你的情况下,它发现char也被认为是8位整数,因此渲染器开始从内存地址104开始加载字符,直到找到\0。因此,当分配内存不足时,它会崩溃。

  

如果我在printf中的my_pointer中没有使用星号(“第一个字符是%c”,my_pointer),那会有什么不同;

Ans :正如我已经说过的那样; char也是一个8位无符号整数,因此编译器认为你提供了一个char(因为my_pointer返回内存地址,如果你还记得是整数)并尝试渲染它;但不幸的是,没有这样的可打印的字符,所以你看到一个空白。

  

在第二个代码中,my_pointer变量在{printf(“%s \ n”,my_pointer);}中没有使用星号(*)。在这段代码中my_pointer是指array_of_words变量的地址还是my_pointer里面的内容?

答案:我之前的话应该回答这个问题

  

为什么输出是'一'而不是'o'?

答案:您在字符串中有\0个,printf搜索\0以了解该字符串已结束。所以第一次找到空值;它终止渲染。

答案 3 :(得分:1)

假设string变量位于内存地址100。 在C中,自动附加NUL字符(\ 0)。

string 
|-------|
|hello\0|
|-------|
100

char *my_pointer = string;

可分为2个陈述:

 char *my_pointer;
 my_pointer = string;

由于my_pointer是指向char的指针,因此my_pointer的值是一个地址 它指向char。

 my_pointer
 |------|
 |100   |
 |------|

*my_pointer是一种类似加法或减法的操作。  它意味着转到该内存地址并获取值。这有一个奇特的名字:DEREFERENCING。

*my_pointer检索内存地址为100的第一个字符h。现在为什么只是h?不是其余的?这是因为printf()要求使用%c格式说明符的字符。如果你想要整个字符串,可以用

来完成
  printf("%s\n", my_pointer );  

请注意,没有解除引用字符。在这种情况下,my_pointer成为100的内存地址。由于有%s格式说明符,它将从内存地址100读取,直到NUL字节字符为' \ 0'。这标志着字符串的结束。

转到第二个示例,array_of_words有3个字符串。字符串的定义是当字符以\0(NUL字符)结束时。

让我们说array_of_words存储在200的内存地址中。

 array_of_words
 |-----------------|
 |one\0two\0three\0|
 |-----------------|
 200



char *my_pointer=array_of_words;

 my_pointer
 |------|
 |200   |
 |------|

printf("%s \n",my_pointer);

returns characters starting from memory address of 200 till '\0' character.

这就是one仅出现的原因。

希望我能正确解释并希望它能帮助你更好地理解。

指针是一个非常具有挑战性的主题。有关于这个主题的书籍。