为什么 dd++/d++ 在非动态分配的数组中不起作用?

问题描述

嘿,我是 C 的初学者,我正在尝试理解指针 我创建了一个程序,在该程序中我衰减数组 arr1 中的指针 d ,然后我衰减了指向 d 指针中的指针 dd 的指针。 我的目的是在非动态分配的数组中使用指向指针的指针打印单词。 第一个程序打印所有单词 第二个程序只打印第一行 第三个程序打印第一行和一些奇怪的符号 我知道这是一种不寻常的方式,但我很好奇为什么 d++ 或 dd++ 在非动态分配的数组中不起作用?

一个节目

#include<stdio.h>
#include<stdlib.h>


int main()
{
    int i=0;
    char arr1[5][10]={"ball","wall","window","table","tv"};
    

    printf("\n");



    char *d;
    char **dd=&d;
    for(i=0; i<5; ++i){
        d=arr1[i];
        printf("array[%d] contains: %s\n",i,*dd);
    }

return 0;
}

第二个程序

#include<stdio.h>
#include<stdlib.h>


int main ()
{
    
    int i=0;
    char arr1[5][10]={"ball","tv"};
    printf("\n");
    char *d;
    d=&arr1[0][0];
    char **dd;
    dd=&d;
    for(dd=&d ; *dd ; dd++)
    {
        printf("\nthe words are %s",*dd); 
        d++; 
    }
    
    
    return 0;
}

第三个程序

#include<stdio.h>
#include<stdlib.h>


int main ()
{
    
    int i=0;
    char arr1[5][10]={"ball",*dd); 
         
    }
    
    
    return 0;
}

解决方法

dd 首先指向 d。 **valueofdis the address ofarr1so when you dereferencedd`,您将获得一个指向数组开头的指针,您可以使用该指针来打印单词“ball”。没关系。

但是当您第一次使用 dd 增加 dd++ 时,它将指向 d 之后的位置。该位置与数组无关,并且该位置没有 char*,因此取消引用 dd 是未定义的行为。

换句话说,dd++ 没有任何意义,因为 d 是单个字符指针。

顺便说一句:请注意,您的循环中还有两个 dd++

,

在第一个程序中,for 循环每次迭代中的指针 d 被分配了存储在数组 arr1 中的每个字符串的第一个字符的地址。

for(i=0; i<5; ++i){
    d=arr1[i];
    ^^^^^^^^^^
    printf("array[%d] contains: %s\n",i,*dd);
}

同时保存在指针dd中的值没有被改变,指针dd仍然指向指针d

在第二个程序中,指针 dd 由指针 d 的地址初始化。但是指针dd递增后会指向指针d之后的内存。结果 for 循环具有未定义的行为。

d=&arr1[0][0];
char **dd;
dd=&d;
for(dd=&d ; *dd ; dd++)
                  ^^^^
{
    printf("\nthe words are %s",*dd); 
    d++; 
}

循环中的这条语句

    d++; 

不影响指针dd,因为在增加指针dd之后,它还没有指向指针d

第三个程序也存在同样的问题。那是在 for 循环中增加指针 dd 之后

for(dd=&d ; *dd ; dd++)

它指向指针 d 之外的内存并使用表达式 *dd 调用未定义的行为。

您可以使用以下方法使用指针来输出存储在二维字符数组中的字符串。

#include <stdio.h>

int main(void) 
{
    enum { N = 10 };
    char arr1[][N] = { "ball","wall","window","table","tv" };
    
    const size_t M = sizeof( arr1 ) / sizeof( *arr1 );
    
    for ( char ( *d )[N] = arr1; d != arr1 + M; ++d )
    {
        puts( *d );
    }
    
    return 0;
}

程序输出为

ball
wall
window
table
tv

用于表达式中的数组指示符在极少数例外情况下被转换为指向其第一个元素的指针。

由于数组 arr1 的类型为 char[5][10],因此数组的元素类型为 char[10]。指向此类对象的指针的类型为 char ( * )[10]。递增指针,它将指向数组的下一个元素。取消引用该指针,如演示程序中所示

puts( *d );

我们得到了char[10]类型数组的指向元素。但是在表达式中用作例如 puts 调用的参数,它又被转换为指向数组(字符串)第一个元素的指针,并且类型为 char *