c/c++小知识点
2021-04-12 18:27
标签:print index 大小 链式 main 库函数 空间 ++ 必须 编写一个标准的strcpy函数 malloc分配完内存后: 【剖析】 【数组名的本质如下:】 要改变一个变量的值,要传地址,例如你改变int a的值,你传&a,改变 int *a 你就指针的地址,也就是二级指针 对于返回值是内置类型的函数来说,即使是非const类型,其返回值也不会被修改。无论是否有const修饰,其函数的返回值都是右值。 [ ] 文件包含 #include :按系统指定的目录检索,常用于包含库函数的头文件,用#include ""也能找到,但增加了编译时间 C++支持重载,而c语言不支持,原因? C编译器,提供了几个特殊形式的预定义宏,在实际编程中可以直接使用,很方便。 FILE 宏所在文件的源文件名 c/c++小知识点 标签:print index 大小 链式 main 库函数 空间 ++ 必须 原文地址:https://www.cnblogs.com/vivian187/p/13347717.html
strcpy函数
#include
出现该错误的原因为:strcpy会导致数组越界
1.在c语言中,string可以用作变量名。C++不可以,string是关键字
2.strcpy的意思是:把字符串strSrc中的内容拷贝到string中,连字符串结束标志‘\0‘也一起拷贝,这样strSrc在内存中的存放为0123456789+\0,所需的空间为11个字节,而string是10个字节,因此会存在数组越界的情况
char * strcpy(char *strDest, const char *strSrc)//将源字符加const,表明其为输入参数,加2分
{
//对源地址和目的地址加非空判断,加3
assert((strDest != NULL) && (strSrc != NULL));
char * address = strDest;
while((*strDest++ = *strSrc++) != ‘\0‘);
return address; // 为了实现链式操作,将目的地址返回,加3分?
}
// strcpy返回目标串的地址,这个返回值的目的是可以使strcpy用在链式表达式中(链式就是一连串写下来的意思。。。),增加灵活性
// 比如
// char s1[]="12345";
// char s2[100];
// int len;
// len=strlen(strcpy(s2,s1+1)); //从s1的第二个字符开始复制内容到s2,并且计算出s2的长度
malloc
1.注意判空
2.一定要free
3.将该指针设为NULL,不然会变成野指针
#include
变量与0比较
BOOL型变量:
if (!var)
int型变量:
if (0 == var)
float型变量:
const float EPSINON = 0.00001;
if (var >= -EPSINON && var
数组名
#include
fun(char *str)函数中数组名作为函数形参时,在函数体内,数组名失去了本身的内涵,仅仅只是一个指针;在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。
(1)数组名指代一种数据结构,这种数据结构就是数组;
例如:
char str[10]; cout << sizeof(str) << endl; 输出结果为10,str指代数据结构char[10]。
(2)数组名可以转换为指向其指代实体的指针,而且是一个指针常量,不能作自增、自减等操作,不能被修改;
char str[10];
str++; //编译出错,提示str不是左值
(3)数组名作为函数形参时,沦为普通指针。
64位平台下,指针的长度(占用内存的大小)为8字节,故sizeof(str) 、sizeof(pStr)都为8。
// 64位系统,这个位数指的是CPU里面的通用寄存器的数据宽度为64位,也就是说一个地址占二进制位数是64,所以sizeof(double*)==sizeof(int*)==sizeof(char*)==64位/8==8字节
// 32位系统,同理,他的一个地址占32位二进制空间,sizeof(double *)==sizeof(int *)==sizeof(char *)==32/8==4
// Bit意为"位"或"比特",是计算机运算的基础;
// Byte意为"字节",是计算机文件大小的基本计算单位;
// 1byte=8bits,两者换算是1:8的关系。
// 两个字节一个汉字。
// 1Bit=1/16个字
// 所以16bit=1个汉字
函数形参
void GetMemory(char *p) {/*改变p的值*/}
void GetMemory_1(char **p) {/*改变p的值*/}
void GetMemory_2(char *&p) {/*改变p的值*/}
char *str = NULL;
GetMemory(str);//传入形参并不能改变形参的值
GetMemory_1(&str);//传地址,可以改变形参的值
GetMemory_2(str);//传引用,可以改变形参的值
或者使用引用调用
局部变量作为函数返回值
char *GetMemory(void)
{
char p[] = "hello world!";
return p;
}
//上述用法错误
//p是一个数组名,属于局部变量,存储在栈中,在函数结束后,内存被释放,函数返回的指向p的内容也不确定
//p局部变量存储在动态存储区,在函数调用时动态分配内存,调用完成后销毁
// 可以这样修改
//1:
char *p = "hello world!";
return p; //函数返回p存储的地址
//2:
static char p[] = "hello world!";
return p;// 改为静态变量,存储在静态存储去,在程序结束后释放
int func()
{
return 1;
}
int i = func();
//有一个临时对象来保存func()函数的返回值1,之后将临时对象的值赋给i。
//编译器将所有的临时对象自动成为const。所以,对于返回值为值类型的函数,其返回值func()为右值。
当函数的返回值是引用类型时,其返回值即为return的变量,所以不需要临时对象保存其返回值。所以,对于返回值为引用类型的函数,其返回值为左值。#include
#include
#include
指向常量的指针不能用于改变其所指向对象的值。想要存放常量对象的地址,只能使用指向常量的指针。const double pi = 3.14;
double *ptr = π//错误,ptr是非const指针
const double *cptr = π//正确
常量指针的本身是常量,必须初始化,而且一旦初始化,则它本身的值就不会改变。int errNumb = 0;
int* const curErr = &errNumb;//curErr是常量指针,且一直指向errNumb
指向常量的常量指针指向一个常量对象,且该指针本身也是常量。const double* const pip = π
const char* get_string()
{
return "12345";
}
// 函数get_string()返回从字符串字面值中建立的const char*。在编译器建立了该字符串并且将其存储在静态存储区之后,该返回值返回的是该字符串字面值在静态存储区中的地址。
// 所以get_string()函数的返回值是右值,且不能为非const指针赋值。
get_string()[0] = ‘a‘; //错误,表达式必须是可修改的左值
char* pstring = get_string();//错误,“const char*”类型不能用于初始化“char*”类型的实体
const char* cpstring = get_string();//正确
// 另外还需要注意的是,函数不能返回指向局部栈变量的指针,因为栈变量在函数返回后就销毁了,其返回的地址为无效地址。
// 将“5返回值是指向常量的指针的函数”中提到的get_string()const char* const get_string()
const char* const get_string()
{
return "12345";
}
// 因为该返回值是指向常量的,所以像在“5返回值是指向常量的指针的函数”中提到的一样,该值为右值,不能对其进行赋值,也不能将其赋值给非const指针。
// const char* const ccpstring = get_string();//正确
// const char* cpstring = get_string();//正确
// 从上面代码可知,指向常量的常量指针可以赋值给指向常量的非常量指针
文件包含和宏
#include "":常用于包含自定义的头文件。先在.cpp文件所在目录去搜索包含的.h文件,用#include 也能找到,但增加了编译时间
./是当前目录
../是父级目录
/是根目录
// 预编译宏
#ifndef XXXXX_H
#define XXXXX_H
#endif
// 作用是防止被重复引用
因为函数被C++编译后在symbol库中的名字与c语言不同。
???例如void fun(int x, int y);
???C编译器编译后在symbol库中的名字为_fun,C++编译器则会产生像_fun_int_int之类的名字。_fun_int_int这种名字包含了函数名和函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。
???为了实现C和C++的混合编程,C++提供了C连接交换指定符号extern "C"来解决名字匹配问题,实现C++代码调用其他C语言代码。#ifdef __cplusplus // 告诉编译器,如果定义了__cplusplus(即如果是cpp文件,因为cpp文件默认定义了该宏),
extern "C"{ // 告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
#endif
/*…*/
#ifdef __cplusplus
}
#endif
#define 宏名 一段符号
示例:#define PI 3.141926
为什么使用宏定义?
方便修改和管理,不用一个一个的去改,也是一种参数化的思想。宏定义不作语法检查,只有在编译被宏展开后的源程序才会报错,注意如果是表达式,一定用要用括号括起来。
FUNCTION 宏所在函数名
LINE 宏所在行的行号
DATE 代码编译的日期
TIME 代码编译的时间