首页 > C语言指针 百思不得其解的一个问题

C语言指针 百思不得其解的一个问题

各位大神 最近在学指针遇到了个问题 为什么上面输出就不用 * 而下面就用*呢 我感觉指针是一直要用 *才能输出里面的内容的

char str[100] = "abcd";
    char *p = &str;
    printf("%s\r\n",p);




    int num = 3;
    int *a = #
    printf("\r\n%d",*a);


对于题主我感觉指针是一直要用 *才能输出里面的内容的这个说法,其实是不恰当的。

指针和其它所有的变量一样,都是一种变量类型,都有标识符两个属性。所有的值都是数字(因为计算机只能存01,01可以很直接转换为十进制数)。这个值如果直接读,是完全混乱的。比如,10是什么?我即可以说是数字10,也可以是ascii码为10的那个字符,还可以是指针(其指向地址为10的那个变量)。所以,标识符变量类型绑定,三者共同解释一个变量。说这么多,就一句:变量都是统一的

对于指针,也是一个这样通用的变量。题中的p*p与,*aa其实没有本质区别。

printf("%s\r\n",p)%s表示输出从第二个参数(即p)指向(p甚至不是指针都可以,C语言只是愚蠢地去得到p的值,然后找到地址为这个值的字符,这个就表示p指向的字符)的那个字符开始,一直到\0结束 的字符串。
如果你写成printf("%s\r\n",*p),就表示*p指向的地址(注意,不是p指向的地址)而*p的值是一个字符类型,对它的值代表的地址访问是非法不合理的,但c是自由的,应该会允许这样做。

printf("\r\n%d",*a) %d是以十进制输出第二个参数(变量)的值,*a代表以a的值为地址的那个变量。所以,就是输出a指向的那个变量的值,而如果是printf("\r\n%d",a),它输出的就是a的值,也就是是num`变量的地址。
说的比较乱,但都是自己的一些总结。题主不妨多理解下。


下面是我之前学习做的笔记,你凑合看一下

int (*func_p)();//指向int类型函数的指针

int *f();//返回指向int类型指针的函数

int num = 1;

int *p_num;

p_num = # //

*p_num//是取出num的数据

p_num//是取出num的内存地址

&P_num//是取出p_num的内存地址

p_num+1//是对num的内存地址加1 ,因为num是int类型的,占用4个字节,如果原来是0x000004那么加1后就是0x000008(数据只是测试随便写的),而不是对num的值计算

int arr[] = {1,2,3,4};

printf("%d\n",(arr+1));// 数组可以是分配好的连续指针,arr就是这个数组的首地址,对地址+1就是对这个类型+1,如果arr[0]是0x00004那么arr[1]就是0x00008然后前面的就是取地址值。 如果是int arr[][4]也可以写成int *arr[4];

printf("%d\n",*arr+1);//同上

(K&R 423页)

int arr[8][8];//int的数组

int **p;//指向int类型指针的指针

int *p[10];//具有10个元素的数组, 每个元素是一个指向int的指针

int (* p)[10];//一个指针, 指向有10个元素的int类型的数组

int * p[3][4];

int (* p) [3][4];

int (* p[3]) [4]; //具有3个元素的数组, 每个都是指向具有4个元素的int数组的指针

 

char *pd () //返回指向char的指针的函数

char (* pd)()//指向返回类型为char的函数的指针

char (* pd[3])()//由3个指针组成的数组,每个指针指向返回类型为char的函数

int const | const int p =&1 //p不能在修改了, p还可以使用

int const p = 1; //p不能在修改了,p还可以

const 在谁前面,修饰谁

第一个是声明一个常量的指针变量。指向的对象不可以修改但是P的指向可以修改。
第二个是声明一个指针变量P是常量类型,指向不可以修改但是指向的对象可以修改。


这只能说明对指针概念还不是很清楚。指针就是保存内存空间的地址的变量。例如定义指针 int *pr=100;  
那么变量pr的值保存的就是整数100所在空间的地址,假如为5000,则pr=5000;  而*pr表示对pr
指向的内存空间中保存的数据的读写,也就是100。所以要读取100这个数据,就要用*pr,例如:
printf("%d",*pr);
int main(int argc,char *arg[]){
    //保存整数的指针,并分配空间
    int *pr = (int *)malloc(100*sizeof(int));
    *pr = 100;
    printf("pr指向空间的地址为%p,pr指向空间的内容是%d\n\n",pr,*pr);
    free(pr);  //用完指针记得释放
    
    //保存字符串的指针,并分配空间
    char *str = (char *)malloc(100*sizeof(char));
    str = "You are so beautiful!";
    while( *str != '\0' ){
        printf("当前str指向的空间地址:%p,当前str指向空间里保存的数据是%c\n",str,*str++);
    }
    str = NULL;
    free(str);
    return 0;
}

格式化字符串不一样,%s要求指针,%d要求整数


p 实际上是字符指针,如果你要输出 p 指向的内容,就应该加 *,例如:

printf("%c", *p);

但是你在格式参数里使用了%s,表示输出字符串,所以就会尝试一直读取p指向的内容,直到遇到 '\0'。在C语言里使用 char* 表示字符串是一个特例,这个时候你可以把它看做一个整体,就好像:

typedef char *String;

第一个输出中p为指向字符数组的指针,也代表了一个字符串,与printf里的%s匹配故不用
第二个输出中a为指向整型变量的指针,所以
a才与printf里的%d匹配。


数组在堆中分配内存,str本身就是指向数组的第一个元素,赋值后p和str等价, 而普通类型在栈中,赋值后p和a不等价,p指向a,a指向值


基本的数据类型 用的是指,数组 等非基本数据类型就是用指针!
特别是在格式化字符输出的时候,由于指定了格式化需要参数类型,在参数类型不匹配是不会强制转换.
或者是格式化字符需要的参数是指,但是传的是指针,那么它会把传递过去的指针地址当做指来处理!
所以在使用格式化字符输出时需要注意站位符与,参数之间的匹配!

ps:其实我觉得如果是刚学的话,可以重复造下轮子,把printf函数自己亲手实现一次就知道其中的原理了.


用*表示要对该地址进行解引用,解引用就是取到该地址上的值。
但是%s就是需要首地址才能打印整个字符串。如果你对首地址解引用,那就只能取到首地址上的值(第一个字符),这时候你就要用%c了。


%s意味着相应的参数为字符串数组的首地址,也就是str

#include "stdio.h"

int main(void) {
    char str[100] = "abcd";
    char* p = (char*)&str;
    printf("%s %p \n", p, p);
    printf("%s %p \n", str, str);
    return 0;
}

运行以后可以发现,p和str的指是相同的

【热门文章】
【热门文章】