1,指针

指针是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

int    *ip;    /* 一个整型的指针 */
double *dp; /* 一个 double 型的指针 */
float *fp; /* 一个浮点型的指针 */
char *ch; /* 一个字符型的指针 */

指针的大小是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。

指针使用实例:

#include <iostream>
using namespace std;
int main ()
{
int var = ; // 实际变量的声明
int *ip; // 指针变量的声明,只声明未初始化
ip = &var; // 初始化,在指针变量中存储 var 的地址
cout << "Value of var variable: ";
cout << var << endl; //原变量的值是20
// 输出在指针变量中存储的地址
cout << "Address stored in ip variable: ";
cout << ip << endl; //输出的是存储的地址,是地址
// 访问指针中地址的值
cout << "Value of *ip variable: ";
cout << *ip << endl; //加×以后输出的是地址区域对应的内容是值,这叫指针
return ;
}

指针可以为空:

在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为指针。

#include <iostream>

using namespace std;

int main ()
{
int *ptr = NULL; cout << "ptr 的值是 " << ptr ; return ;
}

指针的可变的:可加可减

#include <iostream>
using namespace std;
const int MAX = ;
int main ()
{
int var[MAX] = {, , };
int *ptr;
// 指针中的数组地址
ptr = var;
for (int i = ; i < MAX; i++)
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// 移动到下一个位置
ptr++; //指针指向的内存地址是可以通过计算改变的,我估计用的是相似数据存储位置相近原理
}
return ;
}

产生的结果如下:

Address of var[0] = 0x7ffe3c8e3980
Value of var[0] = 10
Address of var[1] = 0x7ffe3c8e3984
Value of var[1] = 100
Address of var[2] = 0x7ffe3c8e3988
Value of var[2] = 200

指针可以比较大小:

#include <iostream>
using namespace std;
const int MAX = ;
int main ()
{
int var[MAX] = {, , };
int *ptr;
// 指针默认指向的是数组中的第一个元素,第一个元素的地址,而不是整个数组
ptr = var;
int i = ;
while ( ptr <= &var[MAX - ] ) //指针只要比var[2]小就继续向下移动
{
cout << "Address of var[" << i << "] = ";
cout << ptr << endl;
cout << "Value of var[" << i << "] = ";
cout << *ptr << endl;
// 指向上一个位置
ptr++; //指针向下一个元素移动,数组中的内存地址是有讲究的,它们按顺序排列,所以可以通过++的方式获取下一个元素
i++;
}
return ;
}

指针数组:

个人觉得指针数组有两种,一种是创建一个数组用以存储多个指针,如下:

#include <iostream>
using namespace std;
const int MAX = ;
int main ()
{
int var[MAX] = {, , };
int *ptr[MAX]; //创建一个指针数组,长度为3
for (int i = ; i < MAX; i++)
{
ptr[i] = &var[i]; // 把指针数组中的元素挨个赋值为var数组中元素的地址
}
for (int i = ; i < MAX; i++) //遍历指针数组,取值输出
{
cout << "Value of var[" << i << "] = ";
cout << *ptr[i] << endl;
}
return ;
} 返回:
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
 

另一个是创建一个数组不存储值,而是存储值存放的内存位置:

#include <iostream>
using namespace std;
const int MAX = ;
int main ()
{
const char *names[MAX] = { //声明并且初始化一个指针数组
"Zara Ali",
"Hina Ali",
"Nuha Ali",
"Sara Ali",
};
for (int i = ; i < MAX; i++)
{
cout << "Value of names[" << i << "] = ";
cout << names[i] << endl; //此处要注意,上一个例子打印出内存地址对应的值用的是:*数组名[索引号],而此处不能这样用,原因不明,但是如果用*name[i]打印出来的将会是ZHNS,首字母,大约是因为指针指向数组的首个吧,但是name[i]为何能打印出值来,就不得而知了
}
return ;
} 返回
Value of names[0] = Zara Ali
Value of names[1] = Hina Ali
Value of names[2] = Nuha Ali
Value of names[3] = Sara Ali

指针可以指向指针:

声明:

int **var;

实例:

#include <iostream>
using namespace std;
int main ()
{
int var;
int *ptr;
int **pptr;
var = ;
// 获取 var 的地址
ptr = &var;
// 使用运算符 & 获取 ptr 的地址
pptr = &ptr;
// 使用 pptr 获取值
cout << "var 值为 :" << var << endl; //3000
cout << "*ptr 值为:" << *ptr << endl; //3000
cout << "**pptr 值为:" << **pptr << endl; //3000
return ;
}

指针传递给函数:

只要声明函数的时候说明是指针就可以了

#include <iostream>
#include <ctime>
using namespace std;
void getSeconds(unsigned long *par); //声明了是无符号常整型的指针,也可以传递数组,
int main ()
{
unsigned long sec;
getSeconds( &sec ); //用的时候传递进去的是地址
// 输出实际值
cout << "Number of seconds :" << sec << endl;
return ;
}
void getSeconds(unsigned long *par)
{
// 获取当前的秒数
*par = time( NULL ); //实际参数会被改变
return;
} 返回:
Number of seconds :1294450468

从函数返回指针:

首先要定义一个返回指针的函数,其次要知道,c++不支持返回纯局部变量,除非局部变量为static

#include <iostream>
#include <ctime>
#include <cstdlib> using namespace std; // 要生成和返回随机数的函数
int * getRandom( )
{
static int r[]; // 设置种子
srand( (unsigned)time( NULL ) );
for (int i = ; i < ; ++i) //数组是长度为10的int数组
{
r[i] = rand();
cout << r[i] << endl;
} return r;
} // 要调用上面定义函数的主函数
int main ()
{
// 一个指向整数的指针,因为返回的是指针所以返回的值也必须由指针存储
int *p; p = getRandom();
for ( int i = ; i < ; i++ ) //数组打印出第一个来就行了
{
cout << "*(p + " << i << ") : ";
cout << *(p + i) << endl;
} return ;
}

2,引用

引用约等于浅拷贝,是原来的变量的别名,所以引用不能为空,引用不能改变,引用必须在创建的时候被初始化,函数不能返回一个局部变量的引用,static例外

比如:

int i = ;
int& r = i;
//r 是一个初始化为 i 的整型引用

实例:

#include <iostream>
using namespace std;
int main ()
{
// 声明简单的变量
int i;
double d;
// 声明引用变量,引用不可为空说的是引用必须是某个变量的别名
int& r = i;
double& s = d;
i = ;
cout << "Value of i : " << i << endl;
cout << "Value of i reference : " << r << endl;
d = 11.7;
cout << "Value of d : " << d << endl;
cout << "Value of d reference : " << s << endl;
return ;
}

函数返回一个引用实例:

#include <iostream>
using namespace std;
double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0};
double& setValues( int i ) //从函数的声明和初始化就能看出来这个函数要返回的是个引用
{
return vals[i]; // 返回第 i 个元素的引用
}
// 要调用上面定义函数的主函数
int main ()
{
cout << "改变前的值" << endl;
for ( int i = ; i < ; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
setValues() = 20.23; // 改变第 2 个元素
setValues() = 70.8; // 改变第 4 个元素
cout << "改变后的值" << endl;
for ( int i = ; i < ; i++ )
{
cout << "vals[" << i << "] = ";
cout << vals[i] << endl;
}
return ;
} 返回:
改变前的值
vals[0] = 10.1
vals[1] = 12.6
vals[2] = 33.1
vals[3] = 24.1
vals[4] = 50
改变后的值
vals[0] = 10.1
vals[1] = 20.23
vals[2] = 33.1
vals[3] = 70.8
vals[4] = 50

引用也可以作为参数:

声明函数的时候这样做就可以了:

void swap(int& x, int& y);

3,日期和时间

c++比c多了处理日期和时间的相关函数和结构,可引用<ctime>,有四个与时间相关的类型:clock_t、time_t、size_t 和 tm

序号 函数 & 描述
1 time_t time(time_t *time);
该函数返回系统的当前日历时间,自 1970 年 1 月 1 日以来经过的秒数。如果系统没有时间,则返回 .1。
2 char *ctime(const time_t *time);
该返回一个表示当地时间的字符串指针,字符串形式 day month year hours:minutes:seconds year\n\0
3 struct tm *localtime(const time_t *time);
该函数返回一个指向表示本地时间的 tm 结构的指针。
4 clock_t clock(void);
该函数返回程序执行起(一般为程序的开头),处理器时钟所使用的时间。如果时间不可用,则返回 .1。
5 char * asctime ( const struct tm * time );
该函数返回一个指向字符串的指针,字符串包含了 time 所指向结构中存储的信息,返回形式为:day month date hours:minutes:seconds year\n\0。
6 struct tm *gmtime(const time_t *time);
该函数返回一个指向 time 的指针,time 为 tm 结构,用协调世界时(UTC)也被称为格林尼治标准时间(GMT)表示。
7 time_t mktime(struct tm *time);
该函数返回日历时间,相当于 time 所指向结构中存储的时间。
8 double difftime ( time_t time2, time_t time1 );
该函数返回 time1 和 time2 之间相差的秒数。
9 size_t strftime();
该函数可用于格式化日期和时间为指定的格式。

实例来一波:

#include <iostream>
#include <ctime> using namespace std; int main( )
{
// 基于当前系统的当前日期/时间,time_t是ctime中类似于数据类型的一种结构,而time()返回的是1990年至今有多少秒
time_t now = time(); // 把 now 转换为字符串形式,字符串dt是对时间now的一种引用
char* dt = ctime(&now); cout << "本地日期和时间:" << dt << endl; // 把 now 转换为 tm 结构
tm *gmtm = gmtime(&now); //这个看起来是指针,函数返回一个指向time的指针
dt = asctime(gmtm); //据说是格林尼治的时间
cout << "UTC 日期和时间:"<< dt << endl;
}

输出格式化的当前时间:

//这个完全看不懂

#include <iostream>
#include <ctime>
#include <stdlib.h>
#include <stdio.h> using namespace std; string Get_Current_Date(); int main( )
{
// 将当前日期以 20** - ** - ** 格式输出
cout << Get_Current_Date().c_str() << endl; getchar();
return ;
} string Get_Current_Date()
{
time_t nowtime;
nowtime = time(NULL); //获取日历时间
char tmp[];
strftime(tmp,sizeof(tmp),"%Y-%m-%d %H:%M:%S",localtime(&nowtime));
return tmp;
}

4,输入和输出

I/O库重要的头文件:

头文件 函数和描述
<iostream> 该文件定义了 cin、cout、cerr 和 clog 对象,分别对应于标准输入流、标准输出流、非缓冲标准错误流和缓冲标准错误流。
<iomanip> 该文件通过所谓的参数化的流操纵器(比如 setw 和 setprecision),来声明对执行标准化 I/O 有用的服务。
<fstream> 该文件为用户控制的文件处理声明服务。我们将在文件和流的相关章节讨论它的细节。

标准输出流:cout

#include <iostream>
using namespace std;
int main( )
{
char str[] = "Hello C++";
cout << "Value of str is : " << str << endl;
}

标准输入流:

#include <iostream>
using namespace std;
int main( )
{
char name[];
cout << "请输入您的名称: ";
cin >> name; //用户的输入赋值给name,类似于python的input
cout << "您的名称是: " << name << endl;
}

标准错误流:cerr 对象是非缓冲的,且每个流插入到 cerr 都会立即输出。不大明白用法,且先看吧

#include <iostream>
using namespace std;
int main( )
{
char str[] = "Unable to read....";
cerr << "Error message : " << str << endl;
}

标准日志流:clog 对象是缓冲的。这意味着每个流插入到 clog 都会先存储在缓冲在,直到缓冲填满或者缓冲区刷新时才会输出。

#include <iostream>
using namespace std;
int main( )
{
char str[] = "Unable to read....";
clog << "Error message : " << str << endl;
}

良好的编程实践告诉我们,使用 cerr 流来显示错误消息,而其他的日志消息则使用 clog 流来输出。

5,数据结构

C/C++ 数组允许定义可存储相同类型数据项的变量,但是结构是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。

可用struct定义结构,以下是结构实例:

struct Books
{
char title[];
char author[];
char subject[];
int book_id;
} book;
//声明一个结构体类型 Books,变量为 book:

用英文点号访问结构成员,

#include <iostream>
#include <cstring>
using namespace std;
// 声明一个结构体类型 Books
struct Books
{
char title[];
char author[];
char subject[];
int book_id;
};
int main( )
{
Books Book1; // 定义结构体类型 Books 的变量 Book1
Books Book2; // 定义结构体类型 Books 的变量 Book2
// Book1 详述
strcpy( Book1.title, "C++ 教程"); //strcpy字符串拷贝命令,把第二个字符串的值赋值给第一个,相当于给books结构的book1实例的第一个属性----title赋值为‘c++教程’
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = ;
// Book2 详述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = ;
// 输出 Book1 信息
cout << "第一本书标题 : " << Book1.title <<endl; //输出的时候基本格式是实例加.加结构内容
cout << "第一本书作者 : " << Book1.author <<endl;
cout << "第一本书类目 : " << Book1.subject <<endl;
cout << "第一本书 ID : " << Book1.book_id <<endl;
// 输出 Book2 信息
cout << "第二本书标题 : " << Book2.title <<endl;
cout << "第二本书作者 : " << Book2.author <<endl;
cout << "第二本书类目 : " << Book2.subject <<endl;
cout << "第二本书 ID : " << Book2.book_id <<endl;
return ;
}

结构作为函数的参数:

#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books book ); //声明一个函数,参数是结构
// 声明一个结构体类型 Books
struct Books
{
char title[];
char author[];
char subject[];
int book_id;
};
int main( )
{
Books Book1; // 定义结构体类型 Books 的变量 Book1
Books Book2; // 定义结构体类型 Books 的变量 Book2
// Book1 内容赋值
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = ;
// Book2 内容赋值
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = ;
// 输出 Book1 信息
printBook( Book1 ); //直接把结构传递进去就行了,不用加struct
// 输出 Book2 信息
printBook( Book2 );
return ;
}
void printBook( struct Books book ) //函数实现
{
cout << "书标题 : " << book.title <<endl;
cout << "书作者 : " << book.author <<endl;
cout << "书类目 : " << book.subject <<endl;
cout << "书 ID : " << book.book_id <<endl;
}

指向结构的指针:

#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books *book ); //函数声明,声明需要一个结构的实例的指针
struct Books //预定义结构的内容
{
char title[];
char author[];
char subject[];
int book_id;
};
int main( )
{
Books Book1; // 定义结构体类型 Books 的变量 Book1
Books Book2; // 定义结构体类型 Books 的变量 Book2
// Book1 详述
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = ;
// Book2 详述
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = ;
// 通过传 Book1 的地址来输出 Book1 信息
printBook( &Book1 ); //因为需要的是指针,所以要把book1 book2 的内存地址放进去
// 通过传 Book2 的地址来输出 Book2 信息
printBook( &Book2 );
return ;
}
// 该函数以结构指针作为参数
void printBook( struct Books *book )
{
cout << "书标题 : " << book->title <<endl; //此处要特别注意,访问指针指向的实例中的结构内容的话,不能继续用点号了,要用->号,不用问为啥,因为是规定
cout << "书作者 : " << book->author <<endl;
cout << "书类目 : " << book->subject <<endl;
cout << "书 ID : " << book->book_id <<endl;
}

补充typedef:

typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。这里的数据类型包括内部数据类型(int,char等)和自定义的数据类型(struct等)。在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

//(1)用typedef声明一个新类型名来代替已有的类型名。如
typedef int Status //指定标识符Status代表int类型
typedef double DATE //指定标识符DATE代表double类型
int i; Status i; //等价的 //(2)用typedef对数组类型起新名:
typedef int NUM[];//声明NUM为整数数组类型,可以包含100个元素
NUM n;//定义n为包含100个整数元素的数组,n就是数组名 //(3)对一个结构体类型声明一个新名字:
typedef struct //在struct之前用了关键字typedef,表示是声明新类型名
{
int month;
int day;
int year;
} TIME; //TIME是新类型名,但不是新类型,也不是结构体变量名,这样就可以用TIME定义该结构体变量,如:
TIME birthday;
//不用typeof的时候:
struct Books //Books是结构体类型
{
char title[];
char author[];
char subject[];
int book_id;
} book; //book是结构变量

c++指针,引用,日期,输入输出和数据结构的更多相关文章

  1. paip.指针 引用 c++ java的使用总结.

    paip.指针 引用  c++ java的使用总结. ///////////////一般一个变量包括下面的信息 a.地址(指针)  b.命名(引用,别名)   c.变量内容.. 指针是一个变量的地址, ...

  2. Delphi函数翻译成VC要注意句柄指针传递(传递Handle的时候,必须加上一个指针引用,才能消除编译错误)

    Delphi里做了魔法变化,每个变量名称本身就是指针,因为不怎么需要指针语法.我也不知道是不是因为这个原因引起的Delphi与VC对句柄的不同处理. 这是Delphi的强行关机函数,好用,调用方式:W ...

  3. C语言学习笔记 (007) - 数组指针和通过指针引用数组元素的方法总结

    1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢? ]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/ 拓展:有指针类型元素的数组称为指针数组. 2.通过指针引用数组元素的 ...

  4. C++中的二级指针和指针引用函数传参

    在函数的使用过程中,我们都明白传值和传引用会使实参的值发生改变.那么能够通过传指针改变指针所指向的地址吗? 在解决这个问题之前,也许我们应该先了解指针非常容易混淆的三个属性: ①.指针变量地址(&am ...

  5. 引用、数组引用与指针引用、内联函数inline、四种类型转换运算符

    一.引用 (1).引用是给一个变量起别名 定义引用的一般格式:类型  &引用名 = 变量名: 例如:int a=1;  int  &b=a;// b是a的别名,因此a和b是同一个单元 ...

  6. C++ 指针引用

    //指针引用 #include<iostream> using namespace std; struct Teacher{ ]; int age; }; int InitA(Teache ...

  7. c语言——数组指针和通过指针引用数组元素的方法总结

    1.数组指针:即指向数组的指针 那么, 如何声明一个数组指针呢?int (* p)[10]; /*括号是必须写的,不然就是指针数组:10是数组的大小*/1拓展:有指针类型元素的数组称为指针数组. 2. ...

  8. C++函数形参为指针和指针引用的区别

    区别: 1.指针传参被调用函数的指针变量在栈内存中重新申请内存. 2.指针引用传参被调用函数的指针变量与调用函数的指针变量共用一块空间. // PointerCite.cpp : 定义控制台应用程序的 ...

  9. C++学习笔记1_ 指针.引用

    1.引用的本质struct typeA{ int &a;}struct typeB{ int *a;}int main(void){ cout<<sizeof(struct typ ...

  10. C++二级指针和指针引用传参

    前提 一级指针和引用 已经清晰一级指针和引用. 可参考:指针和引用与及指针常量和常量指针 或查阅其他资料. 一级指针和二级指针 个人觉得文字描述比较难读懂,直接看代码运行结果分析好些,如果想看文字分析 ...

随机推荐

  1. KMP(模板)

    算法讲解: KMP算法最浅显易懂 模板来源: 从头到尾彻底理解KMP 首先:KMP的模板为: void get_next(char *a, int *nex) { nex[] = ; , j = ; ...

  2. C#的结构和数组

    下面我们继续学习C#的语法.结构struct,C#中的结构和我们PLC中建立的UDT(结构体)是一样的.里面存储了相关的不同类型的数据. 有一句话我觉得十分重要:方法是依存于结构和对象存在的.这以后我 ...

  3. 理解LDAP与LDAP注入

    0x01 LDAP简介 LDAP,轻量目录访问协议 |dn :一条记录的位置||dc :一条记录所属区域||ou :一条记录所属组织||cn/uid:一条记录的名字/ID| 此处我更喜欢把LDAP和 ...

  4. Hive0.13_函数

    Hive函数大全 一.关系运算: 1. 等值比较: = 2. 等值比较:<=> 3. 不等值比较: <>和!= 4. 小于比较: < 5. 小于等于比较: <= 6 ...

  5. MySQL安装版安装过程

    步骤1 步骤2 步骤3 步骤4 步骤5 步骤6 步骤7 步骤8 步骤9 步骤10 步骤11 步骤12

  6. navicat连接mysql8.0+版本报错2059

    ERROR 2059 : Authentication plugin 'caching_sha2_password' cannot be loaded 问题: 连接Docker启动的mysql出现:E ...

  7. 01:认识QT

    Qt: Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架.它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器.Qt是面向对象的框架,使用特 ...

  8. 巨杉内核笔记(一)| SequoiaDB 会话(session)简介

    SequoiaDB 会话(session)简介 会话(Session)的基本概念 容易弄混淆的两个概念是会话与连接. 通俗来讲,会话(Session) 是通信双方从开始通信到通信结束期间的一个上下文( ...

  9. 15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码)

    15分钟带你了解前端工程师必知的javascript设计模式(附详细思维导图和源码) 前言 设计模式是一个程序员进阶高级的必备技巧,也是评判一个工程师工作经验和能力的试金石.设计模式是程序员多年工作经 ...

  10. error C2825: '_Iter': 当后面跟“::”时必须为类或命名空间 -- 原因可能是参数错误或者自定义函数名和库函数名冲突

    今天运行程序的时候遇到了下面这个bug > B1020.cpp >e:\vs2013\vs2013_rtm_ult_chs\data\vc\include\xutility(): erro ...