欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

程序员文章站 2022-06-03 13:14:33
...

代码1: 

#include <stdio.h>

#define va_list void*
#define va_start(arg, start)   arg = (va_list)( ((char*)&start) + sizeof(start) )
void print( char* format, ...)
{
	va_list arg;
    printf("%d\n", *(int*)(va_start(arg, format)) );
}


void main()
{
  char *p = "123";
  print("%s",4);
}

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

arg=(va_list)( ((char*)& format) + sizeof(format) )// sizeof(format)4字节,(char*)的作用只加1字节

比如& format的地址为100,加上(char*)” ((char*)& format) + sizeof(format)”的地址为104

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

*(int*)(va_start(arg, format))的解析//void*类型转换为(int *)一维指针,指向((char*)&format)+ sizeof(format)这个地址,通过*取得里面的值

代码输出结果:4


Printf(“%s”,…)和printf(“%c”,…)的区别

Printf(“%s”,数据的内存地址)

例如:

char a[5] = "123";

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

 


Printf(“%c”,)

例如:

char a[5] = "123";

printf("%s\n", *a );


代码2: 

#include <stdio.h>

#define va_list void*
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))//
void print( char* format, ...)
{
	va_list arg;
	char ch;
	char *str;
    printf("%s\n", *(int*)(va_start(arg, format)) );
}


void main()
{
  char *p = "123";
  print("%s",p);//与代码1不同的地方
}

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

此时,值4变为了字符串“123”的首地址,在通过%s打印出来

代码输出结果:123


代码3:

#include <stdio.h>

#define va_list void*
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))//
void print( char* format, ...)
{
	va_list arg;
	char ch;
	char *str;
    printf("%s\n", *(int**)(va_start(arg, format)) );//不同于代码2的地方
}


void main()
{
  char *p = "123";
  print("%s",p);
}

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

通过对代码2和代码3的比较,可以发现,都是对(va_start(arg, format))里面的值进行解析,却有不同的方式。代码3此时利用(int**)一个二维指针指向“123”的首地址,*(int**)取到“123”的首地址,**(int**)取到首地址里面的值1.这时候需要用printf("%c\n", **(int**)(va_start(arg, format)) )打印里面的值而不是通过“%s”来打印

运行结果:123


代码4:

#include <stdio.h>

#define va_list void*
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))//
void print( char* format, ...)
{
	va_list arg;
	char ch;
	char *str;
    printf("%s\n", *(int*)(va_start(arg, format)) );//不同于代码3的地方
}


void main()
{
  char *p = "123";
  print("%s",p);
}

 

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

对比代码4与代码3,此时我们把(va_start(arg, format))里面的值通过(int *)解析为一维指针,通过*(int*)取得“123”的首地址,因为是一维指针所以不能使用**(int*)(va_start(arg, format))取得里面的值1

运行结果:123


代码5: 

#include <stdio.h>

#define va_list void*
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))//
void print( char* format, ...)
{
	va_list arg;
	char ch;
	char *str;
    printf("%s\n", *(int****)(va_start(arg, format)) );//与代码3,4不同的地方
}


void main()
{
  char *p = "123";
  print("%s",p);
}

运行结果:123

va_start(arg, format)里面的值的值解析为5维指针,只不过可以对里面的值进行5次解引用,这时可以视情况而使用,例如


三维指针指向的使用

#include <stdio.h>

#define va_list void*
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))//
void print( char* format, ...)
{
	va_list arg;
	char ch;
	char *str;
        printf("%s\n", **(int***)(va_start(arg, format)) );//指向三维指针
	printf("%c\n", ***(int***)(va_start(arg, format)) );//取最后的值1
}


void main()
{
  char *str = "123";
  char **p = &str;
  print("%s",p);
}

运行结果:123

                   1

是否了解printf("%s",....)与printf("%c",...)的区别,指针的强制转换成一维指针和二维指针甚至多维指针时如何正确使用

*(int***):取得str变量的地址

**(int***):取得“123”的首地址

***(int***):值1

总结:任何地址都可以转换成多维指针,例如

 

int a;

(int *)&a;//转换成一维指针

(int **)&a//转换成二维指针

(int ***)&a;//转换成三维指针

int a[3] = {0};

(int *)a;//转换成一维指针

(int **)a;//转换成二维指针

并分析指向内存块中的值通过*解引用取出来

如有不当之处,恳请指出一共探讨

参考链接:

(char **)的详解

数组指针