您的位置:首页 > 编程语言 > C语言/C++

c/c++的笔记(看到想记录的就添加)

2016-07-12 23:27 204 查看

1.size_t

size_t 类型定义在cstddef头文件中,该文件是C标准库的头文件stddef.h的C++版。它是一个与机器相关的unsigned类型,其大小足以保证存储内存中对象的大小。

例如:bitset的size操作返回bitset对象中二进制位中的个数,返回值类型是size_t。

例如:在用下标访问元素时,vector使用vector::size_type作为下标类型,而数组下标的正确类型则是size_t。vector使用的下标实际也是size_t,源码是typedef size_t size_type。

一个基本的无符号整数的C / C + +类型, 它是sizeof操作符返回的结果类型, 该类型的大小是选择。因此,它可以存储在理论上是可能的任何类型的数组的最大大小。 换句话说,一个指针可以被安全地放进为size_t类型(一个例外是类的函数指针,但是这是一个特殊的情况下)。 size_t类型通常用于循环、数组索引、大小的存储和地址运算。 虽然size_t可以存储一个指针,它的目的是更好地使用另一个unsinged整数类型uintptr_t形式。 在某些情况下,使用size_t类型是更为有效,比习惯性使用无符号类型的程序员更安全。

size_t是在基于无符号整数memsize类型的C / C + +的标准库中定义的。 C语言中,此类型位于头文件stddef.h中,而在C++中,则位于cstddef中。

在C++中,设计 size_t 就是为了适应多个平台的, 经测试发现,在32位系统中size_t是4字节的,而在64位系统中,size_t是8字节的,这样利用该类型可以增强程序的可移植性。

2.智能指针

参考这个http://blog.csdn.net/hackbuteer1/article/details/7561235

3.字符数组结束符和sprintf等函数的使用中容易出现的问题

char [10] 这样的字符数组,若是赋值”0123456789”,就出错了,最多只能赋值9个字符,因为后面需要放置一个结束符’\0’

sprintf这样的函数

char buf[4];

int i=1294967295;//32位系统

sprintf(buf,”%d”,i);//完蛋了

或者这样

char buf[4];

int i=129;

sprintf(buf,”%4ld”,i);

//很难说了,也许一直不出现问题,也许出现了问题也找不到原因,看具体平台上int和long int 是不是一样操作

4,虚函数

class A{
public:
virtual void print(){ cout<<”This is A”<<endl;}
};

class B:public A{
public:
void print(){ cout<<”This is B”<<endl;}
};

int main(){
A a;
B b;
A* p1=&a;
A* p2=&b;
p1->print();
p2->print();
}


这样输出的结果就是This is A和This is B

指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。

5.strtok函数

函数返回第一个分隔符分隔的子串后,将第一参数设置为NULL,函数将返回剩下的子串

6.引用和取地址

在C++中,既有引用又有取地址,好多人对引用和取地址不是很清楚,因此也无法区分。其实他们的区别可以用一句话概括:和类型在一起的是引用,和变量在一起的是取址。下面我们通过实例具体了解一下

1)引用在赋值=的左边,而取地址在赋值的右边,比如

int a=3;

int &b=a; //引用

int *p=&a; //取地址

2)和类型在一起的是引用,和变量在一起的是取址。 举例同样如上,还有下例:

int function(int &i)

{

} //引用

3)对于vector,上面2条同样适合

vector vec1(10,1); //initialize vec1: 10 elements, every element’s value is 1

vector &vec2 = vec1; // vec2 is reference to vec1

vector *vec3 = &vec2; //vec3 is addresss of vec1 and vec2

7.C语言中.和->区别

#include <stdio.h>
struct _UnionTest {
unsigned int i;
unsigned char ch[2];
};

int main() {
struct _UnionTest uniontest;
struct _UnionTest *p;  //指针
p = &uniontest;

uniontest.i = 0;
uniontest.ch[0] = 1;
uniontest.ch[1] = 2;
printf("%d ", uniontest.i);
printf("%d\t%d\n", uniontest.ch[0], uniontest.ch[1]);针引用
p->i = 100;
p->ch[0] = 200;
p->ch[1] = 300;
printf("%d ", uniontest.i);
printf("%d\t%d\n", uniontest.ch[0], uniontest.ch[1]);
return 0;
}


//两个区别就是在一个是普通成员引用…一个是指针引用

8.字符串详解

http://www.cnblogs.com/KingOfFreedom/archive/2012/12/07/2807223.html

一、C语言中,为什么字符串可以赋值给字符指针变量

char *p,a=’5’;

p=&a; //显然是正确的,

p=”abcd”; //但为什么也可以这样赋值??

问:一直理解不了为什么可以将字串常量赋值给字符指针变量,请各位指点!

答:

双引号做了3件事:

1.申请了空间(在常量区),存放了字符串

2. 在字符串尾加上了’/0’

3.返回地址

你这里就是 返回的地址 赋值给了 p

二、

char *p = “hello”;

上边的表达式为什么可以,而把p换成数组,然后再赋值就不行了

解释:

字符串常量”hello”出现在一个表达式中时,”hello”表达式使用的值就是这些字符所存储的地址(在常量区),而不是这些字符本身。

所以,可以把字符串赋值给指向字符的指针p,而不能把字符串赋值给一个字符数组。

char a[10] = “hello”; //这样可以,这种情况是c语言初始化所支持的

如果写成char a[10]

然后 a = “hello” 这样就错误了。

同样是a数组,char a[10] = “hello”;这种是数组的初始化,和a[0] = ‘h’ a[1] = ‘e’…是一个道理

但是换成char a [10]

然后a = “hello”就不行了 “hello”赋值的值是一个地址,而a虽然也有地址,但是这与指针是不一样的,指针的值是地址,而数组的值虽然也是地址,但是却是一个常量,所以不能给常量赋值。

代码测试

#include <stdio.h>
int main()
{
char *p = "hello";
printf("%s",p);
char a[10];
a = "hello";
return 0;
}


error C2440: ‘=’ : cannot convert from ‘char [6]’ to ‘char [10]’

There is no context in which this conversion is possible

看到这样的错误提示,你是否会想到把char a[10]改成char a[6]呢

试一下,

error C2106: ‘=’ : left operand must be l-value

运算符的左边应该是一个“左值”。所谓“左值”就是指在程序中占用内存空间、可以被修改的量,比如各种变量。

继续扩展问题:

在使用指针的时候,指针可以自增,而数组不能自增

编译器给数组分配了空间,数组a的地址就是一个常量了,让常量自增这肯定是不行的。

继续扩展:

在指针自增的时候,编译器会自动识别类型,比如指针是指向int型的,想获取下一个的地址时,指针直接p++就行了,不要多此一举的p+4了

特别需要注意的是,在void指针使用的时候,不能使用指针运算,应为void型编译器不能识别类型的长度(即指针所指对象的体积),p++这样就是不合法的,即不能进行数学运算,也不能使用*取值操作,想使用必须转换为其它的类型

三、标题:对字符数组,字符指针,字符串常量

原帖地址:http://anypath.blog.sohu.com/25069424.html

1.以字符串形式出现的,编译器都会为该字符串自动添加一个0作为结束符,如在代码中写

“abc”,那么编译器帮你存储的是”abc\0”

2.”abc”是常量吗?答案是有时是,有时不是。

不是常量的情况:”abc”作为字符数组初始值的时候就不是,如

char str[] = “abc”;

因为定义的是一个字符数组,所以就相当于定义了一些空间来存放”abc”,而又因为

字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为

char str[3] = {‘a’,’b’,’c’};

又根据上面的总结1,所以char str[] = “abc”;的最终结果是

char str[4] = {‘a’,’b’,’c’,’\0’};

做一下扩展,如果char str[] = “abc”;是在函数内部写的话,那么这里

的”abc\0”因为不是常量,所以应该被放在栈上。

是常量的情况: 把”abc”赋给一个字符指针变量时,如

char* ptr = “abc”;

因为定义的是一个普通字符指针,并没有定义空间来存放”abc”,所以编译器得帮我们

找地方来放”abc”,显然,把这里的”abc”当成常量并把它放到程序的常量区是编译器

最合适的选择。所以尽管ptr的类型不是const char*,并且ptr[0] = ‘x’;也能编译

通过,但是执行ptr[0] = ‘x’;就会发生运行时异常,因为这个语句试图去修改程序

常量区中的东西。

记得哪本书中曾经说过char* ptr = “abc”;这种写法原来在c++标准中是不允许的,

但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许,

但是建议的写法应该是const char* ptr = “abc”;这样如果后面写ptr[0] = ‘x’的

话编译器就不会让它编译通过,也就避免了上面说的运行时异常。

又扩展一下,如果char* ptr = “abc”;写在函数体内,那么虽然这里的”abc\0”被

放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的,

只不过是它所指向的东西被放在常量区罢了。

3.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。

如char s1[3]和char s2[4],s1的类型就是char[3],s2的类型就是char[4],

也就是说尽管s1和s2都是字符数组,但两者的类型却是不同的。

4.字符串常量的类型可以理解为相应字符常量数组的类型,

如”abcdef”的类型就可以看成是const char[7]

5.sizeof是用来求类型的字节数的。如int a;那么无论sizeof(int)或者是sizeof(a)都

是等于4,因为sizeof(a)其实就是sizeof(type of a)

6.对于函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通的指针类型,如对于void func(char sa[100],int ia[20],char *p)

则sa的类型为char*,ia的类型为int*,p的类型为char*
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c-c++ c语言