指针

变量与地址

变量给谁用的?

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

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

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

指针与指针变量

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

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

#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. [bzoj3585] Rmq Problem / mex

    [bzoj3585] Rmq Problem / mex bzoj luogu 看上一篇博客吧,看完了这个也顺理成章会了( (没错这篇博客就是这么水) #include<cstdio> # ...

  2. ES6中对象新增的方法

    属性的简洁表示法 ES6 允许在大括号里面直接写入变量和函数,作为对象的属性和方法.这样的书写更加简洁. const foo = 'bar'; const baz = { foo }; console ...

  3. Citus 分布式 PostgreSQL 集群 - SQL Reference(查询分布式表 SQL)

    如前几节所述,Citus 是一个扩展,它扩展了最新的 PostgreSQL 以进行分布式执行.这意味着您可以在 Citus 协调器上使用标准 PostgreSQL SELECT 查询进行查询. Cit ...

  4. 数据库连接Database link?

    在一个用户下,可以获取到另外的用户下的表的数据,通常在跨数据库时使用. create database link link93 connect to scott identified by tiger ...

  5. 下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d"?

    对于如下代码: String s1 = "a"; String s2 = s1 + "b"; String s3 = "a" + " ...

  6. java-规约-集合

    /** * 1 * @hashCode&equals的处理: * 1-只要覆写了equals,必须复写hashCode. * 2-因为Set存储的是不重复的对象,依据hashCode和equa ...

  7. 解决Project出来的问题

    问题显现: 解决办法: 恢复默认布局

  8. 获取Java数据库中结果集的每个字段名和个数

    /** * 查询到多条数据, 封装到List<Map> */public List<Map<String, Object>> queryForMapList(Str ...

  9. servlet中的ServletConfig对象

    ServletConfig对象对应web.xml文件中的<servlet>节点.当Tomcat初始化一个Servlet时,会创建ServletConfig对象,并将该Servlet的配置信 ...

  10. 【前端小技巧】利用border画三角形及梯形

    border是围绕元素内容和内边距的一条或多条线,border 属性允许你规定元素边框的样式.宽度和颜色 值: border-width 粗细 none/hidden/solid/dashed/dot ...