C++及计算机基础知识 - 02

以后要坚持刷题了,太久不用C++,很生疏。还要一些计算机的基础知识,也忘得差不多了。我计划将做题过程中遇到的问题记录下来,写成系列,方便以后翻看。

1 补码

几个特性:

补码的正零与负零表示方法相同;

对一个整数的补码再求补码,等于该整数自身;

正整数的补码是其二进制表示,与原码相同;

求负整数的补码,将其原码除符号位外的所有位取反(0变1,1变0,符号位为1不变)后加1。

比如-15,用八位表示,就是10001111,除了符号位都取反,就是11110000,加1就是11110001,所以-15的补码就是11110001。

2 C++整数二进制和十进制转换

找到一个方便的用法:

unsigned int a = 43261596;
bitset<32> bs(a);
cout << bs << endl;

输出是00000010100101000001111010011100,这个是LeetCode 190题的题目中的。不过这样用了bitset库,下面再用另一个方法试试。

for (int i = 0; i < 32; i++)
{
    cout << ((a >> i) & 1);
}

这个的输出就和题目要求的一样的了,是二进制形式的反序列,想要正序列则要从32开始到0这么个顺序。

这个题应该是可以直接用字符串翻转头尾实现的,无需别的操作。比如:

string reverseString(string targetString)
{
    string tmpString = "";
    int targetStringLength = targetString.length();

    for (int i = targetStringLength; i > 0; i--)
    {
        tmpString += targetString[i - 1];
    }

    return tmpString;
}

不过运行的时候发现有代码要求,就是这样的:

class Solution {
public:
    uint32_t reverseBits(uint32_t n) {
        
    }
};

所以就不能用字符串的方式了。那么题目其实描述是不准确的,不是输入二进制串,而是输入整数,如43261596,然后输出也要整数才行。那么写成这个样子:

uint32_t reverseBits(uint32_t n)
{
    unsigned int tmp = 0;

    for (int i = 0; i < 32; i++)
    {
        if (((n >> i) & 1) == 1)
        {
            tmp += (1 << (32 - 1 - i));
        }
    }
    
    return tmp;
}

头一次在LeetCode刷题,也不用管输入输出了,不错。

3 vector的使用

LeetCode题目,序号为1的简单题:

#include 
#include 

using namespace std;

class Solution {
public:
	vector twoSum(vector& nums, int target)
	{
		vector result;
		vector::iterator it;
		vector::iterator innerIt;
		int i = 0, j = 0;

		for (it = nums.begin(); it != nums.end() - 1; it++)
		{
			j = i + 1;

			for (innerIt = it + 1; innerIt != nums.end(); innerIt++)
			{
				if (*it + *innerIt == target)
				{
					result.push_back(i);
					result.push_back(j);
				}

				j++;
			}

			i++;
		}

		return result;
	}
};

int main()
{
	Solution solution;
	int numsArray[] = { 2, 7, 11, 15 };
	vector numsVector(numsArray, numsArray + 5);

	vector::iterator it;
	vector result = solution.twoSum(numsVector, 26);

	for (it = result.begin(); it != result.end(); it++)
	{
		cout << *it << endl;
	}

	return 0;
}

这里可以用push_back存放结果,不过一开始数据很多的话就可以用一个数组存好然后直接给vector赋初值。

4 for循环

一般写for循环分三段,今天见个两段的,突然有些不太确定了,再理一下。

for (int i = 5; i--;)
{
    std::cout << i << std::endl;
}

首先,一个分号是一段,两个分号分成三段,所以这段代码 i-- 是第二段,而第三段则留空了。for循环先执行第一段,比如这里 i 就是5了;然后执行第二段,这里 i 自减变成了4;然后执行函数体打印,然后执行第三段,也就是空。最终输出是4,3,2,1,0。那为什么没有继续减下去呢,比如一开始就是-5,就能一直减下去;一开始是-5自增的话也就只能到0就停止了。这是因为一般写for循环,第二段是判断如小于多少,第三段才是自增自减;而这里代码中 i-- 是有值的,它就是个布尔值了相当于。在C++中,if语句对于0就认为是假不执行,像是 -1或者正值1,2,3等就认为是真,可以执行。

5 引用

引用不能为空,指针可以为空。比如:

int& a;  // 错误,引用必须初始化

int n;

int& b = n;  // 正确

6 string.h和cstring

.h头文件是旧标准,如stdio.h可以用新的:

#include

替换,就是将.h去掉并在开头添加了“c”,所以string.h就变成了cstring,含有strcpy等方法。同时,C++还有一个:

#include

这个是C++标准定义的头文件,它定义了string类型,支持字符串的size()等方法。

7 __cplusplus

c++中定义了__cplusplus,而c中则没有。c语言和C++编译的函数不同,许多时候就用__cplusplus配合extern "C"的方式,让C++编译器按照c的编译格式来进行编译。

8 sizeof

sizeof对int求大小,就是4,x86和x64都是这个结果。而sizeof对int*求大小,x86下就是4,x64下是8,也就是说,指针在x86下占用4个字节,x64下占用8个字节。因为指针是地址,4个字节和8个字节正好是对应了32位和64位寻址。

9 *和&

如:

int*p = a;

则输出p得到00CF840,就是a的地址,输出*p则得到123,就是a的值。

输出&p则是00F6F8F4,这个地址就是指针的地址,输出*&p得00CF840,就是a的地址。

所以输出**&p得到的就是123,即a的值,*&就是指针的引用。

10 指针常量和常量指针

常量指针,指向常量,但是指针可以修改指向别处:

const char* ptr;

指针常量,指针不能再指向别处,但地址中的值可变:

char* const ptr;

const离谁近,谁就不能修改。

11 类的成员函数访问类实例的私有成员

如:

String& String::operator=(const String& rhs)

它的参数rhs是另一个String类型实例,但是可以在该操作符重载的时候访问其私有成员,如私有的pstr,仍然可以用rhs.pstr访问。主要就是如下几种:

a. 在C++的类的成员函数中,允许直接访问该类的对象的私有成员变量。

b. 在类的成员函数中可以访问同类型实例的私有变量。

c. 拷贝构造函数里,可以直接访问另外一个同类对象(引用)的私有成员。

d. 类的成员函数可以直接访问作为其参数的同类型对象的私有成员。

你可能感兴趣的:(C++,C++,计算机基础知识)