关于C语言指针的那点事

#include<stdio.h>
#include<string.h>

/*
//当需要多路信息返回时,一个输入型参数,一个输出型参数,还有一对返回值判断。 (int a/int *p/return 0/-1)
int main()
{
int a, b = 0, ret = -1;
a = 10;
ret = multip5_3(a, &b);
if (ret == -1)
{
printf("出错了\n");
}
else
{
printf("result = %d.\n", b);
}
}


int multip5_3(int a, int *p)
{
int tmp;
tmp = 5 * a;
if (tmp > 100)
{
return -1;
}
else
{
*p = tmp;
return 0;
}
}
*/






/*
//const的具体用法
void func3(char *p);
//void func4(const char *p);
void func3( char *p)
{
*p = 'a';
}


/*
void func4(const char *p)
{
*p = 'a';
}


int main()
{
//char *pStr = "linux";// 编译不报错
char pStr[] = "linux";// ok的
func3(pStr);
printf("%s.\n", pStr);
}




*/
/*
//函数传参用使用const指针
void func1(int *p);
//void func2(const int *p);


void func1(int *p)
{
*p = 5;
}


/*
void func2(const int *p)
{
*p = 5;
}


int main()
{
int a = 1;
func1(&a);
//func2(&a);
printf("a=%d.\n",a);
}
*/
/*
//函数传参
int main()
{
int a=5;
int b;
b= multip(a);
printf("result=%d.\n",b);
}
int  multip(int c)
{
return c*2;
}
*/


/*
//传址调用(既可以传值,也可以改变值)
void swap(int *a,int *p)
{
int temp=0;
temp = *a; //temp变量=(*a)指针变量的值。
*a = *p; //(*a)指针变量解引用=(*p)指针变量的值
*p =temp; //(*p)指针变量解引用=temp变量
}


int main ()
{
int x=3,y=5;
swap(&x,&y);
printf("x=%d y=%d.\n",x,y);
}
*/

/*
//传值调用(只能传值而不能改变值)
int swap(int a,int b)
{
int temp=0;
temp = a;
a = b;
b = temp;
}


int main()
{
int x=3,y=5;
swap(x,y);

printf("x=%d y=%d.\n",x,y);
}
编译后 x和y并没与变换,还是一样的。
x=3 y=5.
*/


/*
//用结构体指针变量进行函数传参
struct A
{
char a; // 结构体变量对齐问题
int b; // 因为要对齐存放,所以大小是8
};
void func5(struct A *a1)
{
printf("sizeof(a1) = %d.\n", sizeof(a1)); // a1是一个指针变量,所以这个变量占内存4个字节:4
printf("sizeof(*a1) = %d.\n", sizeof(*a1)); // *a1在这里是指针变量解引用的意思,所以该指向的是结构体a变量的大小:8
printf("&a1 = %p.\n", &a1); // 本身a1就是一个指针变量,这里&a1表示的是地址的地址所以是二重指针。
printf("a1 = %p.\n", a1); // 这个打印出来就是a1地址
printf("a1->b = %d.\n", a1->b); // 指针调用成员是通过“->”来调用的:5555
}
int main()
{
struct A a = 
{
.a = 4,
.b = 5555,
};
printf("sizeof(a) = %d.\n", sizeof(a)); // 这里和下面是一样的:8
printf("&a = %p.\n", &a); //结构体变量的地址
printf("a.b = %d.\n", a.b); //结构体成员变量的值:5555
func5(&a); //函数用结构体指针变量来进行传参。 //通过形参(结构体指针)取地址在调用函数时关联的。
}
编译结果:
sizeof(a) = 8.
&a = 0xbf864c08.
a.b = 5555.
sizeof(a1) = 4.
sizeof(*a1) = 8.
&a1 = 0xbf864bf0.
a1 = 0xbf864c08.
a1->b = 5555.
*/






/*
//用结构体变量进行函数传参
struct A //A:结构体类型
{
int a; //4字节     结构体变量对齐问题
char b; // 因为要对齐存放,所以大小是8
};


void func (struct A c)
{
printf("sizeof(c)=%d.\n",sizeof(c)); //打印(c变量长度)出来是sizeof(c)=8.
printf("&c=%p.\n",&c); //打印(c变量地址)出来是编译器分配的一个地址。
printf("c.a=%d.\n",c.a); //打印是5。
printf("c.b=%c.\n",c.b);
}


int main ()
{
struct A c = //c:作为结构体A类型的变量c
{
5,
55
};
printf("sizeof(c)=%d.\n",sizeof(c)); //打印(c变量长度)出来是sizeof(c)=8.
printf("&c=%p.\n",&c); //打印(c变量地址)出来是编译器分配的一个地址。
printf("c.a=%d.\n",c.a); //打印是5。
printf("c.b=%c.\n",c.b); //打印是7,具体看ASCLL表。
func(c);


return 0;
}
*/


/*
//数组进行函数传参(数组和指针式一样的)
int main()
{
int a[5];
printf("a=%p.\n",a);
func(a);
return 0;
}


int func(int *p)
{
printf("*p = %d.\n",sizeof(p));
printf("in func  address =%p.\n",p);

}
*/


/*
//普通变量进行函数传参
int main()
{
int a=4;

FUNC(a);
return 0;
}


int FUNC(int c)
{

printf("a=%d.\n",c);
}
*/


//当我们想要一个数组的所有元素个数时就这样做。
/*
int main()
{
int a[56];
int b;
b = sizeof(a)/sizeof(a[0]);
printf("b=%d.\n",b);
}
*/


/*
//#define dpChar char * 两者有什么区别 
//typedef char  *tpChar typedef用来重命名类型,或者说用来制造用户自定义类型


#define dpchar char *
typedef char* tpchar;


int main()
{
dpchar p1,p2; //等价于char *p ,  b
tpchar p3,p4; //等价于  int*p , int*b
printf("sizeof(p1) = %d.\n", sizeof(p1)); // 4
printf("sizeof(p2) = %d.\n", sizeof(p2)); // 1
printf("sizeof(p3) = %d.\n", sizeof(p3)); // 4
printf("sizeof(p4) = %d.\n", sizeof(p4)); // 4
}
*/




/*


void func2(int *a, int num);


void func2(int *a, int num)
{
printf("数组大小=%d.\n",sizeof(a)); //4
printf("num=%d.\n",num); //80
// 在子函数内,a是传进来的数组的指针(首地址)
// 在子函数内,num是数组的大小
}


int main()
{
int a[20];
func2(a, sizeof(a)); 
}




*/


/*下面两个慢慢体会
void func1(int *a);


void func1(int *a)
{
printf("数组大小=%d.\n",sizeof(a));
}


int main()
{
int a[20];
func1(a); // 4 
}
*/




/*
void func(int a[]);


void func(int a[])
{
printf("数组大小=%d.\n",sizeof(a));
}


int main()
{
int a[20];
func(a); // 4 因为a在函数func内部就是指针,而不是数组
}
*/




/*
//char *p=str     最后一个还不是很好理解个人觉得
int main()
{
char str[] = "hello"; 
char *p =str;
//printf("p=%d.\n",sizeof(p)); //4 相当于sizeof(char *)
//printf("*p=%d.\n",sizeof(*p)); //1 相当于sizeof(char)
printf("p=%d.\n",strlen(p)); //5 strlen(str)
}
*/


/*在字符数组中sizeof()、strlen() 的区别
// sizeof(str)  sizeof(str[0])  strlen(str) 单位字节。 
int main()
{
char str[]="char";
printf("str 中的元素个数=%d.\n",sizeof(str)); //5---->字符串左后一位是"/0"
printf("str[0]=%d.\n",sizeof(str[0])); //字符串数组中第0个元素的
printf("str=%d.\n",strlen(str)); //表示的是字符串数组中一共的元素个数
}


*/


/*
int main()
{
//int*->float*  强制类型转换。
int a=5;
float *p;
int *p1;
p1 =&a;
*p1 =55;
p =(float *)p1;


printf("p1=%f.\n",*p);
}
*/


/*
int main()
{
int a=5;
printf("a=%d.\n",a);
printf("a=%f.\n",a); //类型不匹配,编译后发现变量a会通过float的类型来解析。


}
*/


/*
//关于指针和指针类型的解析有关。这个要明白指针所涉及的两个变量,
//一个是变量本身,一个是指针所指向的那个变量
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *p;
p = a;
printf("*(p+1) = %d.\n", *(p+1)); //2
printf("*(p+1) = %d.\n", *((char *)p+1)); //0
printf("*(p+1) = %d.\n", *(int *)((unsigned int)p+1));//乱码
char *p2;
p2 = (char *)p;
printf("*(p+1) = %d.\n", *(p2+1)); //0
}
*/


/*
int main()
{
//数组类型匹配问题
int a[5]={8,5,5,6,2,};
int *p;
p = &a;
printf("a = %x.\n", a); //首元素首地址
printf("&a = %x.\n", &a); //整个数组的地址
printf("&a[0] = %x.\n", &a[0]); //首元素首地址
printf("a[0] = %x.\n", a[0]); //首元素


}
*/




/*
int main()
{
//另一种表示方法,这种更加直观一些。
int a[5]={1,5,5,1,5};
int *p;
p = a;
printf("*p =%d.\n",*p);



int a[5] = {1, 2, 3, 4, 5};
printf("a[3] = %d.\n", a[3]);
printf("*a = %d.\n", *a); //因为“a”做右值时表示的是该数组的首元素首地址,所以可以直接来用
printf("*(a+1) = %d.\n", *(a+1));

}
*/


/*
int main()
{
int a[3]={2,5,4};
int *p;
p =&a[0]; //验证"a"和"&a[0]做右值得时候是一样的"
*p = 45;


printf("a[0]=%d.\n",a[0]);


}
*/






/*
前提是:
int a[5];


a 左值:该数组的所有空间譬如(5*4)=20个字节、右值:该数组的首元素首地址。
a[0] 左值:表示数组第0个元素的内存空间。 右值:该数组的第0个元素的值。
&a 左值:不能做左值,因为&a是一个常量(地址) 右值:整个数组的首地址。
&a[0] 左值:数组对应的首元素对应的内存空间, 右值:该数组的首元素首地址。
*/


/*
int main()
{
int a[3]={0,5,60}; //数组的下标符中的数字表示的是数据的元素的个数,而我们真正在访问时是从0开始的到元素个数-1.
int *p;
p =&a;


*p =555;
printf("a[0]=%d.\n",a[0]);


}
*/










/*
int main()
{
const int a =5;
int *p;
p =(int *)&a; //这里告诉我们如何去骗过编译器进行编译,就是改变被CONST 变量的类型就可以实现。
*p =556;
}
*/


/*
int main()
{


int a =5;
int const *p; //这个const是用来修饰p指针指向的那个变量  location指定的
int * const p1; //这个const是用来修饰p1指针本身的  variable变量
const int *p2; //和int const *p;是一样的
const int * const p3;//这个表示两个都是不可以变得
//实际项目中用const 时,初始化的时候就要把值选好。

}
*/












/*
int main()
{
int *p;
//p =NULL;
//*p = 556;//这段告诉我们当我们定义一个指针变量时,没有关联指针变量
//的话就会发生段错误。





//printf("*p=%p.\n",p);

return 0;
}
*/




/*
int main()
{
int a = 5;
int * p1, *p2; //告诉我们*和int 结合如何定义变量。
p1 =&a;
p2 =&a;
printf("*p1=%p.\n",p1);
printf("*p2=%p.\n",p2);
}
*/




/*
int main()
{
int a = 4; //这里就是告诉我们星号和变量组成的关系。
int * a1;
int*      p;
int        *p1;

a1 =&a; //理解关于左值和右值得关系
p  =&a; //编译器默一个变量做左值的时候是该内存空间,而做右值得时候是该变量的值。
p1 =&a;

printf("*a1=%p.\n",a1);
printf("*p=%p.\n" ,p );
printf("*p1=%p.\n",p1);

return 0;


}
*/


/*这里要理解使用指针需要的步骤:定义一个指针变量,然后做左值去指向一个和指针类型相同的普通变量,
(记住变量做右值得时候是这个变量的内存空间),最后就是解引用了。
int main()
{
int a = 5; //定义一个普通变量并且初始化变量等于5.
int *p=&a; //定义一个指针变量并且初始化指向变量a.1
*p = 56; //解引用
printf(" a= %d.\n",a);
printf("*p=%p.\n",p);   

return 0;
}

*/


/*
//两种一起用,是可以的
  typedef struct student
{
char name[20];
int age;
} student;
// 我们一次定义了2个类型:
// 第一个是结构体类型,有2个名字:struct teacher,teacher
// 第二个是结构体指针类型,有2个名字:struct teacher *, pTeacher
typedef struct teacher
{
char name[20];
int age;
int mager;
}teacher, *pTeacher;


int main()
{
teacher t1;
t1.age = 23;
pTeacher p1 = &t1;
printf("teacher age = %d.\n", p1->age);


struct student *pS1; // 结构体指针
student *pS2; // 同上 return 0;
}
*/



/*
//第二中使用方法,用typedef封装结构体
typedef struct student
{
int a[5];
char p;
}student_init;
int main()
{
student_init inits1;
inits1.p='c';
inits1.a[5]=0,5,2,8,8;
}
*/


/*
//结构体的第一种用法。
struct student
{
int a[5];
char p;

};


int main()
{
struct student inits1;
inits1.p='c';
inits1.a[5]=0,5,2,8,8;
}
*/




/*看样子是学傻了
//字符串这块还要在了解了解
int add(int a, int b);
int sub(int a, int b);
int multiply(int a, int b);
int divide(int a, int b);


//函数指针的一般用法
typedef int (*pFunc)(int, int);


int main(void)
{
pFunc p1 = NULL;
char c = 0;
int a = 0, b = 0, result = 0;
printf("请输入要操作的2个整数:\n");
scanf("%d %d", &a, &b);

printf("请输入操作类型:+ | - | * | / |\n");
do 
{
scanf("%c", &c);
}while (c == '\n');
// 加一句调试
printf("a = %d, b = %d, c = %c.\n", a, b, c);


switch(c)
{
case '+':
p1 = add;  break;
case '-':
p1 = sub;  break;
case '*':
p1 = multiply;break;
case '/':
p1 = divide;  break;
default:
p1 = NULL;  break;
}
result = p1(a, b);
printf("%d %c %d = %d.\n", a, c, b, result);
return 0;
}


int add(int a, int b)
{
return a + b;
}


int sub(int a, int b)
{
return a - b;
}


int multiply(int a, int b)
{
return a * b;
}


int divide(int a, int b)
{
return a / b;
}
*/




/*typedef用法:作用用法简介
// 这句重命名了一种类型,这个新类型名字叫pType,类型是:char* (*)(char *, const char *);
typedef char* (*pType)(char *, const char *);


// 函数指针数组
//typedef char* (*pType[5])(char *, const char *);


// 函数指针数组指针
//typedef char* (*(*pType)[5])(char *, const char *);


int main()
{
char* (*p1)(char *, const char *);
    pType p3;// 等效于 char* (*p3)(char *, const char *);
    p3 = p1;
}
*/


/*将一个char *类型的函数复制过来自己用。
//  char *strcpy(char *dest, const char *src);、
int main()
{
char a[11]="hua xiao lu"; //定义了一个字符数组
char *(*pFunc)(char *, const char *); //定义了一个字符串指针类型的 函数指针
pFunc = strcpy; //将strcpy函数的首地址复制给pFunc
pFunc(a,"abc"); //在使用pfunc函数: SRC:需要传的字符  dest:需要传的数组的地址
printf("a=%s.\n",a);
}
编译后的结果:
a=abc. //说明strcpy函数是可以改变字符串输出的内容的。
*/


/*
//函数指针传值,在被调用的函数名时我们应该加“&”这个时候表示我们取的是这个函数的首地址,不加“&”的时候只是一个函数名。
void func1(void)
{
printf("I am func1.\n");
}


int main(void)
{
void (*pfunc)(void); 
pfunc = &func1; // 左边是一个函数指针变量,右边是一个函数名
//pfunc = &func; //&func1和func1做右值时是一模一样的,没任何区别
pfunc(); // 用函数指针来解引用以调用该函数
 }
 */
 
 
/*
//当我们需要赋值的时候赋值的被赋值的类型都要一致才可以被赋值。
int main()
{
int *p;
int (*p1)[5];
int a[5];

p = a; //类型匹配  
p1 = &a;//类型匹配
}
*/


//函数指针和typedef:说明函数指针其实就是这个函数名和这个函数的首地址绑定在一起了,所以当我们用函数指针的时候其实就是
//在用这个函数在内存中的首地址(实质和普通变量没有什么区别)。




/*
//指针数组、数组指针的概念
int main()
{
int *p[5];   //指针数组:这是个数组所有类型都是指针。 “[] * ” 谁的优先级高和谁靠拢。
int (*p1)[5]; //数组指针:这是个指针,这个指针指向的是一个数组,这个数组有五个元素。
}
*/










































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值