知识点查缺补漏(001)

去除字串中多余的空格

去除掉字符串中多余的空格,字符串的句首和句尾没有空格,中间的字符串单词只能保留一个空格。例如__I___am_____a______student.____(下划线表示空格哈,打多个空格显示的还是一个),最后输出I am a student.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
#include <string>
using namespace std;

char* delBlank(char *s) {
char *p = s;
if (s == nullptr) return s;

// 去除首部空格
while (*p == ' ')
{
p++;
}

// 去除中间空格
int i = 0;
while (*p != '\0')
{
s[i++] = *p++;
while (s[i - 1] == ' ' && *p == ' ')
{
p++;
}
}

int endIndex = (s[i - 1] == ' ') ? (i - 1) : i; // 有可能最后一个还是空格
s[endIndex] = '\0';

return s;
}

int main() {
char s1[] = " I am a student. ";
char s2[] = "";
char s3[] = " ";
char s4[] = "I am a student.";
char s5[] = "I am a student.";

std::cout << delBlank(s1) << std::endl;
std::cout << delBlank(s2) << std::endl;
std::cout << delBlank(s3) << std::endl;
std::cout << delBlank(s4) << std::endl;
std::cout << delBlank(s5) << std::endl;
}

输出:

1
2
3
4
5
I am a student.


I am a student.
I am a student.

关于 char * 内存分配问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;

char* s1() {
char *p = "Hello World";
return p;
}

char* s2() {
char p[] = "Hello World";
return p;
}

char* s3(char **p, int num) {
*p = (char *)malloc(num);
strcpy(*p, "Hello World");
return *p;
}

int main() {

std::cout << s1() << std::endl;
std::cout << s2() << std::endl;

char *p;
std::cout << s3(&p, 100) << std::endl;
}

输出:

1
2
3
Hello World
t龔 // 每次都是随机输出东西
Hello World

解析:
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap)一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。-程序结束后有系统释放
4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。

所以,对于s1函数,里面的 p 指向一个文字常量区,只有程序结束后这内存才会释放,能正确输出。注意,C和C++的标准都规定:任何试图改变字符串常量的行为其结果是未定义的。对于 char *p = "Hello World";,可默认等效为 const char *p = "Hello World"; 改变 const 会导致崩溃。
对于s2函数,里面的 p 指向的是一个栈里面分配的内容,函数调用完毕,栈里面的内容就释放了,所以每次都输出未知内容。
对于s3函数,里面的 *p 是指向一个堆里面分配的内容。执行函数strcpy(*p, "Hello World");的时候,将文字常量区里面的内容 Hello World 拷贝到堆里面(编译器可能会将它与 *p 所指向的 Hello World 优化成一个地方)。而且没对堆进行释放操作,所以正常输出。

fork

  1. fork之后父子进程将共享代码文本段,但是各自拥有不同的栈段、数据段及堆段拷贝。子进程的栈、数据从fork一瞬间开始是对于父进程的完全拷贝、每个进程可以更改自己的数据,而不要担心相互影响!
  2. fork之后父子进程同时开始从fork点向下执行代码,具体fork之后CPU会调度到谁?不一定!
  3. 执行fork之后,子进程将拷贝父进程的文件描述符副本,指向同一个文件句柄(包含了当前文件读写的偏移量等信息)。
  4. 文件描述符在子进程中被关闭,在父进程中还能读写。因为文件表中的每一项都会维护一个引用计数,标识该表项被多少个文件描述符(fd)引用,在引用计数为0的时候,表项才会被删除。所以调用close(fd)关闭子进程的文件描述符,只会减少引用计数,但是不会使文件表项被清除,所以父进程依旧可以访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h> 
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main(void)
{
int fd = open("test.txt", O_RDWR | O_CREAT | O_TRUNC);

if (fork() == 0)
{
close(fd);
exit(0);
}

write(fd, "hello world", strlen("hello world"));

return 0;
}
您的支持将鼓励我继续创作!
0%