指针

变量与地址

变量给谁用的?

变量是对某一块空间的抽象命名。

变量名就是你抽象出来的某块空间的别名。

指针就是地址。指向某个地址。

指针与指针变量

指针是指向某块地址。指针(地址)是常量。

指针变量是可以发生变化的。

#include <stdio.h>

int main()
{
int i = 1;
int *p = &i; printf("i = %d \n", i);
printf("&i = %p \n", &i);
printf(" p = %p \n", p);
printf("&p = %p \n", &p);
printf("*p = %d \n", *p); // 为什么不用char* p = &i; //TYPE NAME = VALUE
//int* p = &i;
//int i = 1; }

直接访问间接访问

占内存空间

都是8字节,linux 64 位中。

空指针 野指针 空类型

int * i= NULL;

指针运算

两个指针同时指向一个数组。++ 、--、比较、关系、&、*

指针与一维数组

数组名和 指针的区别?
a是数组名字是一个表示地址的常量。
指针是一个变量。
a++;
p++;
#include <stdio.h>

int main()
{
int a[3] = {1,2,3};
int *p = a; int i;
for(i = 0;i < sizeof(a)/sizeof(*a); i++) {
printf("%d %d %d %d \n",a[i],*(a+i),p[i],*(p+i)); // a[i]
printf("%p %p %p %p \n",a+i, &a[i],p+i, p+i); // &a[i]
}
printf("\n"); }

这里代码体现什么是指针常量什么是指针变量?

#include <stdio.h>

int main()
{
int a[3];
int i;
int *p = a; for(i = 0;i < sizeof(a)/sizeof(*a); i++) {
printf("%p -> %d\n",&a[i],a[i]);
} for(i = 0;i <sizeof(a)/sizeof(*a); i++) {
scanf("%d",p++);
}
//p = a;
for(i = 0;i < sizeof(a)/sizeof(*a); i++,p++) {
printf("%p -> %d\n",p,*p);
} printf("\n"); }

指针与二维数组

#include <stdio.h>
#include <stdlib.h> int main()
{
int a[2][3] = {1,2,3,4,5,9};
int i,j;
int *p;
//(W) p = a;
//wall等号右边a是在行间跳转的指针
// 等号左边是列间跳转的指针
p = *(a+0);
//p = &a[0][0];//*(a+0),*a; printf("%p->%p \n", a, a + 1);
// printf("%p -> %d \n\n",p,*p); // for(i = 0; i < 6; i++,p++) {
// printf("%d ",*p);
// }
// printf("\n"); for(i = 0;i < 2; i++) {
for(j = 0; j < 3; j++) {
printf("%p->%d\n",&a[i][j],a[i][j]);
printf("%p->%d\n",*(a+i)+j,*(*(a+i)+j));
//printf("%p->%d\n",a[i]+j,*(*(a+i)+j));
//printf("%d ",a[i][j]);
}
printf("\n");
}
exit(0);
}

指针与字符数组

#include <stdio.h>
#include <stdlib.h>
#include <string.h> // 字符指针和字符数组之间的使用 //
// 练习 定义数组后定义指针 后面操作都用指针实现 int main()
{ #if 0
char* str = "hello"; // "hello" 串常量
printf("%d %d \n",sizeof(str),strlen(str));// 8 5
//strcpy(str,"world"); //err 为什么不可以?区分字符指针和字符数组的区别 :企图用"world" 覆盖串常量
str = "world";
puts(str);
#endif #if 0
char str[] = "hello";
printf("%d %d \n",sizeof(str),strlen(str));// 6 5 // (F) str = "hhhh"; // 数组名是一个地址常量怎么可能放到等号左边???
strcpy(str,"jjjj");
puts(str); #endif #if 0
char str[] = "hello world";
char *p = str + 7;
puts(str);
puts(p);
#endif exit(0);
}

const与指针

#include <stdio.h>
#include <stdlib.h>
/*
常见const
const int a;
int const a; const int *p; // 常量指针
int const *p; int *const p; // 指针常量 const int *const p; define 不检查语法
*/ int main()
{
#if 0
// cosnt修饰常规变量的使用特点
// 这个警告已经构成error
const float pi = 1.14159;
// pi = 9999.2;
float *p = &pi; // initialization discards ‘const’ qualifier from pointer target type [enabled by default]
*p = 1223.333333;
// 修改方法 const float *p = &pi; printf("%f\n",pi); // 1223.333333
printf("%f\n",*p);
#endif // 常量指针:指针的指向可以发生变化但是指针所指向的目标值是不能变化的
// const *p
// 值不能变
// 指向可以发生变化 int i = 1;
const int *p1 = &i;
int j = 88; //T i= 10;
//F *p1 = 99;
//T p1 = &j;
printf("%d\n",i);
printf("%d\n",*p1); // 指针常量:指针的指向不能发生变化,指针所指向的目标变量的值可以发生变化。
int i = 1;
int j= 100;
int * const p1 = &i; //T *p1 = 10;
//F p1 = &j;
printf("%d\n",i);
printf("%d\n",*p1); //const 左右都有 指向和值都不能变
int num = 10;
const int* const p3 = &num;
// *p3 = 99;
// p3 = &i; exit(0);
}

指针数组和数组指针的区别

数组指针

#include <stdio.h>
#include <stdlib.h>
/*
数组指针: [存储类型] 数据类型 (* 指针名) [下标] = 值;
int (*p)[3]; -> type name; -> int[3] *p;
*/
int main()
{
// 数组指针 int a[2][3] = {1,2,3,4,5,9};
int i,j;
int *p = *a;
int (*q)[3] = a;
//printf("%d \n", *a); // a[0][0]的地址
//printf("%d \n", **a); //1 #if 0
// printf("%d \n",*p);//q
//int *p = *a;
//printf("%d \n",*p); //q
// int (*q)[3] = a+1;
// printf("%d \n",**q); // 4 printf("\n"); for(i = 0;i < 2; i++) {
for(j = 0; j < 3; j++) {
// printf("%p->%d\n",*(a+i)+j,*(*(a+i)+j));
printf("%p->%d\n",*(q+i)+j,*(*(q+i)+j));
}
printf("\n");
}
#endif }

指针数组:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
int *arr[3]; -> TYPE NAME; -> int *[3] arr; */
int main()
{ char *name[5] ={"english","math","cpp","teacher","computer"}; int i,j;
for(i = 0; i < 5; i++) {
puts(name[i]);
} for(i = 0; i < 5 ;i++) {
int k = i;
for(j = i+1;j < 5; j++) {
if(strcmp(name[k],name[j]) > 0) {
k = j;
}
}
if(k != i) {
char *tmp = name[i];
name[i] = name[k];
name[k] = tmp;
} }
printf("排序后:\n");
for(i = 0; i < 5; i++) {
puts(name[i]);
} exit(0);
}

指针和函数

函数:

echo $? // 显示上个命令的返回值

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */ /* 定义:
int a[N] = {1,2,3,4,5,6};
int *p = a; -> a *a a[0] &a[3] p[i] p *p p+1
-> int* int int int * int int* int int* */
//void func1(int *a,int n)
void func1(int* a,int n,int *b)
{
cout << "== b =" << *b<< endl; // 1
for(int i = 0;i < n; i++)
{
printf("%d ",*(a+i));
}
printf("\n"); return ;
}
int main(int argc, char** argv) {
int arr[3] = {1,2,3}; func1(arr,3,&arr[1]);//&(*(ar+1)) return 0;
}

用指针与一维数组的使用:

void func2(int *p,int n)
{
int m = n / 2;
for(int i = 0;m--;i ++)
{
int j = n - i -1;
int tmp = *(p+i);
*(p+i) = *(p+j);
*(p+j) = tmp;
}
}
int main(int argc, char** argv) {
int arr[] = {1,2,3,6,4,2,38,4,2,23}; //func1(arr,3,&arr[1]);//&(*(ar+1))
func2(arr,10); for(int i = 0;i < 10;i ++)
cout << arr[i] << ' ' ;
cout <<endl; return 0;
}

函数与二维数组:

#include <iostream>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */ /*
int a[M][N] = {......};
int *p = a;
int (*q)[N] = a; -> a[i][j] *(a+i) a[i]+j p[i] *p
int int * int * int int -> q[i][j] *q q p+3 q+2
int int* int(*)[N] int * int (*)[N] */ void func(int *p,int n)
{ for(int i = 0;i < n; i++)
{
cout << *p << ' ';
p++;
} }
void print_arr(int (*p)[3])
{
for(int i = 0;i < 3;i++)
{
for(int j = 0;j < 3;j++)
{
cout << *(*(p+i)+j) << ' ';
}
cout<< endl;
}
}
int main(int argc, char** argv) {
int arr[3][3] = {1,2,3,6,4,2,38,4,2}; func(arr[0],9); // *arr &arr[0][0] arr[0]
// 这里func(arr,9) 形参是int *p 就报错 p是一个列指针,二维数组不一样 print_arr(arr); return 0;
}

案例使用二维数组传参

float average_score(int *a,int n)
{
float sum = 0.0;
for(int i = 0;i < n; i++)
{
sum += *(a+i);
} return sum/n;
}
void find_num(int(*p)[3],int num)
{
for(int i = 0;i < 3 ;i++)
printf("%d ",*(*(p+num) + i));
cout << endl;
return ;
}
int main(int argc, char** argv) {
int arr[3][3] = {1,2,3,6,4,2,38,4,2}; float ave = 0.0;
ave = average_score(*arr,9);
printf("%f \n",ave); find_num(arr,0); return 0;
}

函数与指针关系的详细剖析

  • 指针函数

    • 返回值 * 函数名(参数)
#if 0
void find_num(int(*p)[3],int num)
{
for(int i = 0;i < 3 ;i++)
printf("%d ",*(*(p+num) + i));
cout << endl;
return ;
}
#else
int * find_num(int(*p)[3],int num)
{
return *(p+num);
}
#endif
int main(int argc, char** argv) {
int arr[3][3] = {1,2,3,6,4,2,38,4,2}; float ave = 0.0;
ave = average_score(*arr,9);
printf("%f \n",ave); int * res; res = find_num(arr,0);
if(res != NULL)
{
for(int i = 0;i < 3;i++)
printf("%d ",res[i]);
cout <<endl;
}
else
{
printf("can not find\n");
} return 0;
}
  • 函数指针
#include <iostream>
using namespace std; int add(int a,int b)
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
int main(int argc, char** argv)
{
int a = 2, b = 3;
int (*p)(int,int);
int (*q)(int,int); int ret;
p = add;
q = sub; printf("%d \n",p(a,b));
printf("%d \n",q(a,b)); return 0;
}



回调函数

  • 函数指针数组

    • 类型 (*数组名[下标])(形参);
#include <iostream>
using namespace std; int add(int a,int b)
{
return a+b;
}
int sub(int a,int b)
{
return a-b;
}
int main(int argc, char** argv)
{
int a = 2, b = 3;
int (*funcp[2])(int,int); int ret;
funcp[0] = add;
funcp[1] = sub; for(int i = 0;i < 2; i++)
{
ret = funcp[i](a,b);
printf("%d \n",ret);
} return 0;
}
  • 指向指针函数的函数指针数组

    数组存放指针,指针指向函数,函数返回值是指针类型。

结构体

  • 产生的意义
  • 类型描述
  • 嵌套定义
  • 定义变量、初始化及引用
  • 占用内存大小

定义和使用:

#include <iostream>
using namespace std; #define NAMESIZE 100 struct simp_st
{
int i,j;
float f;
char ch;
}; struct birthday_st
{
int year,month,day;
}; struct student_st
{
int id;
char name[NAMESIZE];
struct birthday_st birthday;
int math;
int chinese;
}; int main(int argc, char** argv)
{ struct student_st stu = {10011,"Alan",{3011,22,11},22,54};
struct student_st *p = &stu;
printf("%d %s %d-%d-%d %d %d \n",stu.id,stu.name,stu.birthday.year,stu.birthday.month,stu.birthday.day,stu.math,stu.chinese);
printf("%d %s %d-%d-%d %d %d \n",p->id,p->name,p->birthday.year,p->birthday.month,p->birthday.day,p->math,p->chinese); struct student_st stu[2] = {{10011,"Alan",{3011,22,11},22,54},{10012,"salay",{2021,2,12},88,66}};
struct student_st *p = &stu[0];// &stu[0] stu
for(int i = 0;i < 2;i++,p++)
{
printf("%d %s %d-%d-%d %d %d \n",p->id,p->name,p->birthday.year,p->birthday.month,p->birthday.day,p->math,p->chinese);
} return 0;
}
  • 内存对齐问题

    addr/sizeof()

构造类型-结构体内存问题及函数传参

为后面linux高级铺垫。

  • 可以实现一个学生管理系统。

  • 产生及意义
  • 类型描述
  • 嵌套定义
  • 定义变量
  • 占用内存大小
  • 函数传参
  • 位域
union 名{
数据类型 成员名1;
数据类型 成员名2;
};
  • 枚举类型
enum 名{
成员1;
成员2;
成员3;
}

C/C++指针、函数、结构体、共用体的更多相关文章

  1. 5、数组&字符串&结构体&共用体&枚举

    程序中内存从哪里来 三种内存来源:栈(stack).堆(heap).数据区(.date): 栈(stack) 运行自动分配.自动回收,不需要程序员手工干预: 栈内存可以反复使用: 栈反复使用后,程序不 ...

  2. C语言高级-结构,共用体,文件,链表

    C语言结构 标准声明方式 struct student{        int age;        char sex;    }; 这个可以在main函数中定义:  struct student ...

  3. C++结构、共用体、枚举

    一.结构 结构是C++OOP的基石.学习有关结构的知识僵尸我们离C++的核心OOP更近. 结构是用户定义的类型,同一个结构可以存储多种类型数据,这使得将一个事物的不同属性构成一个对象成为了可能.另外C ...

  4. C语言基础 (11) 结构体 ,共用体 枚举 typedef

    1 课堂回顾 作用域与生命周期 2 static 局部变量 2 打字游戏 3 内存分区代码分析 4 结构体基本操作 (复合类型[自定义类型 #include <stdio.h> #incl ...

  5. 瘋子C语言笔记(结构体/共用体/枚举篇)

    (一)结构体类型 1.简介: 例: struct date { int month; int day; int year; }; struct student { int num; char name ...

  6. C++复合类型(结构,共用体,枚举)

    •结构是用户定义的类型,而结构的声明定义了这种类型的数据属性. 一.关键字struct声明:   定义了一种新类型 struct inflatable{ char name[20];//结构成员 fl ...

  7. C基础知识(8):结构体、共用体、位域

    结构体 数组允许定义可存储相同类型数据项的变量,而结构体是C编程中另一种用户自定义的可用的数据类型,它允许用户可以存储不同类型的数据项. struct 语句的格式如下: struct [structu ...

  8. 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符

    [源码下载] 不可或缺 Windows Native (8) - C 语言: 结构体,共用体,枚举,类型定义符 作者:webabcd 介绍不可或缺 Windows Native 之 C 语言 结构体 ...

  9. C语言------结构体和共用体

    仅供借鉴.仅供借鉴.仅供借鉴(整理了一下大一C语言每个章节的练习题.没得题目.只有程序了) 文章目录 1 .实训名称 2 .实训目的及要求 3.源代码及运行截图 4 .小结 1 .实训名称 实训8:结 ...

  10. C语言笔记 09_共用体&typedef&输入|输出

    共用体 共用体允许您在相同的内存位置存储不同的数据类型.您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值.共用体提供了一种使用相同的内存位置的有效方式. 定义共用体 为了定义共用体, ...

随机推荐

  1. JavaScript day04 函数

    函数 函数讲解 函数是什么? 函数其实就抽取写好的js代码 作为一个通用的代码块 (封装) 作用: 减少代码冗余 (过多) 方便调用 (提供效率 提高代码的可读性) 便于维护 (二次修改) js有哪些 ...

  2. SpringMVC 和SpringBoot中的注解是如何起作用的,如何实现的

    SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化   https://www.cnblogs.com/leftthen/ ...

  3. fiber核心(react 16)?

    旧: 浏览器渲染引擎单线程, 计算DOM树时锁住整个线程, 所有行为同步发生, 有效率问题, 期间react会一直占用浏览器主线程,如果组件层级比较深,相应的堆栈也会很深,长时间占用浏览器主线程, 任 ...

  4. ServletConfig对象和ServletContext对象有什么区别?

    一个Servlet对应有一个ServletConfig对象,可以用来读取初始化参数. 一个webapp对应一个ServletContext对象. ServletContext对象获取初始化定义的参数. ...

  5. Dubbo 推荐用什么协议?

    dubbo://(推荐) rmi:// hessian:// http:// webservice:// thrift:// memcached:// redis:// rest://

  6. Java 中,编写多线程程序的时候你会遵循哪些最佳实践?

    这是我在写 Java 并发程序的时候遵循的一些最佳实践: a)给线程命名,这样可以帮助调试. b)最小化同步的范围,而不是将整个方法同步,只对关键部分做同步. c)如果可以,更偏向于使用 volati ...

  7. 文件缓存tmpfs + 数据缓存SSDB(一)

    一.文件缓存tmpfs 1.特性 1) 基于内存的文件系统,RAW+SWAP,虚拟内存 2) tmpfs使用虚拟内存,/dev/shm/使用共享内存 3) 访问速度快,可以动态调整大小 4) 没有持久 ...

  8. mysql常见命令参数(一)

    1.mysql命令常用参数 1.--auto-rehash (tab键自动补全,表名及表字段) # mysql -u root --auto-rehash # vim my.cnf [mysql] a ...

  9. 学习RabbitMQ(四)

      I. 消息中间件特点: 1,异步处理模式 消息发送者可以发送一个消息而无需等待响应,消息发送者将消息发送到一条虚拟的通道或队列上,消息接收者则订阅或监听该通道,一条消息可能最终转发给一个或多个消息 ...

  10. Cloud Design Patterns & Architecture Styles

    Cloud Design Patterns Categories Data Management Design and Implementation Messaging Patterns Ambass ...