标签:print index 大小 链式 main 库函数 空间 ++ 必须
#include<stdlib.h>
#include<stdio.h>
#include<string>
int main()
{
char strDst[10];
char *strSrc = "0123456789";
strcpy(strDst, strSrc);
printf("strDst is %s\n", strDst);
return 0;
}
//结果
//strDst is 0123456789
//Abort trap: 6
出现该错误的原因为:strcpy会导致数组越界
1.在c语言中,string可以用作变量名。C++不可以,string是关键字
2.strcpy的意思是:把字符串strSrc中的内容拷贝到string中,连字符串结束标志‘\0‘也一起拷贝,这样strSrc在内存中的存放为0123456789+\0,所需的空间为11个字节,而string是10个字节,因此会存在数组越界的情况
编写一个标准的strcpy函数
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 <stdlib.h>
#include <stdio.h>
#include <string>
void GetMemory(char **p, int num)
{
if(num<=0) {
printf("申请的内存空间要大于零!\n");
}
*p = (char*)malloc(num);
if(*p==NULL) {
printf("申请内存失败!\n");
}
}
int main()
{
char *str = NULL;
GetMemory(&str, 100); // 参数传递使用地址或引用
strcpy(str, "hello world");
printf("%s\n", str);
free(str);
str = NULL;
return 0;
}
BOOL型变量:
if (!var)
int型变量:
if (0 == var)
float型变量:
const float EPSINON = 0.00001;
if (var >= -EPSINON && var <= EPSINON)
指针变量:
if (NULL == var)
#include <iostream>
using namespace std;
void fun(char *str)
{
cout << "fun(str) sizeof: " << sizeof(str) << endl;//结果:8
}
int main()
{
char str[10];
char *ptrStr[10]; //指针数组:每一个元素均为指针
char* pStr = str;
cout << "sizeof(str): \t" << sizeof(str) << endl; //结果:10
cout << "sizeof(ptrStr): \t" << sizeof(ptrStr) << endl; //结果:10*8 = 80
cout << "sizeof(pStr): \t" << sizeof(pStr) << endl;//结果:8
// "\t"表示tab键
fun(str);
return 0;
}
【剖析】
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);//传引用,可以改变形参的值
要改变一个变量的值,要传地址,例如你改变int a的值,你传&a,改变 int *a 你就指针的地址,也就是二级指针
或者使用引用调用
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()为右值。
#include<stdlib.h>
#include<stdio.h>
#include<string>
char& get_val(std::string& str, int index)
{
return str[index - 1];
}
int main()
{
std::string str = "12345";
char ch = get_val(str, 1);
get_val(str, 1) = ‘a‘;
printf("ch is %c\n", ch);
printf("str is %s\n", str.c_str());
return 0;
}
// 结果
// ch is 1
// str is a2345
对于返回值是内置类型的函数来说,即使是非const类型,其返回值也不会被修改。无论是否有const修饰,其函数的返回值都是右值。
#include<stdlib.h>
#include<stdio.h>
#include<string>
char get_val(std::string& str, int index)
{
return str[index - 1];
}
const char get_val2(std::string& str, int index)
{
return str[index - 1];
}
int main()
{
std::string str = "12345";
char ch = get_val(str, 1);//ch的值是‘1‘
get_val(str, 1) = ‘a‘;//编译时报错,expression is not assignable: 左操作数必须为左值
return 0;
}
#include<stdlib.h>
#include<stdio.h>
#include<string>
class X {
int x;
public:
X(int i = 0);
};
X::X(int ii)
{
x = ii;
}
X f1()
{
return X();
}
const X f2()
{
return X();
}
int main()
{
f1() = X(1);//编译时不报错
f2() = X(1);//error: no viable overloaded ‘=‘: 没有找到接受“const X”类型的左操作数的运算符
return 0;
}
// 函数f1()的返回值是非const类型,所以可以对其返回值进行赋值,即返回值是左值;而f2()的返回值是const类型,则不能对其进行赋值,即返回值是右值。
// 对非const类型的返回值进行赋值,虽然可以编译通过,但是实际上这么做没有意义。因为函数的返回值保存在临时对象中,我们无法访问该临时对象,在该行代码执行完毕后,临时对象就会被清除。
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 <> :按系统指定的目录检索,常用于包含库函数的头文件,用#include ""也能找到,但增加了编译时间
#include "":常用于包含自定义的头文件。先在.cpp文件所在目录去搜索包含的.h文件,用#include <>也能找到,但增加了编译时间
./是当前目录
../是父级目录
/是根目录
// 预编译宏
#ifndef XXXXX_H
#define XXXXX_H
#endif
// 作用是防止被重复引用
C++支持重载,而c语言不支持,原因?
因为函数被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
C编译器,提供了几个特殊形式的预定义宏,在实际编程中可以直接使用,很方便。
FILE 宏所在文件的源文件名
FUNCTION 宏所在函数名
LINE 宏所在行的行号
DATE 代码编译的日期
TIME 代码编译的时间
标签:print index 大小 链式 main 库函数 空间 ++ 必须
原文地址:https://www.cnblogs.com/vivian187/p/13347717.html