从大学刚学习c/cpp以来,几年过去了,但是由于大学没有好好深入学习研究c/cpp以及算法,挺后悔的。所以奉劝计算机专业的学生,大学不应该过早步入各种开发的步调,而忽略c/cpp、算法、基础专业知识的学习。其实一开始,最重要的就是把基础打扎实了,编程的思维方式和动手能力很重要,如何将现实问题,通过算法建模转化为代码才是至关重要的,可以视为灵魂。
所以我把自己学习的过程做记录,没事的时候仔细体会,别有一番风味,每次也会有不一样的体会。

指针

先以一段代码开始

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
#include <stdio.h>
int main(int argc, char *argv[])
{
// create two arrays we care about
int ages[] = {23, 43, 12, 89, 2};
char *names[] = {
"Alan", "Frank",
"Mary", "John", "Lisa"
};
// safely get the size of ages
int count = sizeof(ages) / sizeof(int);
int i = 0;
// first way using indexing
for(i = 0; i < count; i++) {
printf("%s has %d years alive.\n",
names[i], ages[i]);
}
printf("---\n");
// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;
// second way using pointers
for(i = 0; i < count; i++) {
printf("%s is %d years old.\n",
*(cur_name+i), *(cur_age+i));
}
printf("---\n");
// third way, pointers are just arrays
for(i = 0; i < count; i++) {
printf("%s is %d years old again.\n",
cur_name[i], cur_age[i]);
}
printf("---\n");
// fourth way with pointers in a stupid complex way
for(cur_name = names, cur_age = ages;
(cur_age - ages) < count;
cur_name++, cur_age++)
{
printf("%s lived %d years so far.\n",
*cur_name, *cur_age);
}
return 0;
}

上面的代码很好的诠释了指正的工作原理,首先

  • 在你的计算机中开辟一块内存。
  • 将ages这个名字“指向”它的起始位置。
  • 通过选取ages作为基址,并且获取位置为i的元素,来对内存块进行索引。
  • 将ages+i处的元素转换成大小正确的有效的int,这样就返回了你想要的结果:下标i处的int。

指针仅仅是指向计算机中的某个地址,并带有类型限定符,所以你可以通过它得到正确大小的数据,指针的用途就是让你手动对内存块进行索引,一些情况下数组并不能做到。绝大多数情况中,你可能打算使用数组,但是一些处理原始内存块的情况,是指针的用武之地。指针向你提供了原始的、直接的内存块访问途径,让你能够处理它们。
指针有四个最基本的操作:

  • 向OS申请一块内存,并且用指针处理它。这包括字符串,和一些你从来没见过的东西,比如结构体。
  • 通过指针向函数传递大块的内存(比如很大的结构体),这样不必把全部数据都传递进去。
  • 获取函数的地址用于动态调用。
  • 对一块内存做复杂的搜索,比如,转换网络套接字中的字节,或者解析文
    其实当我们在阅读别人的代码或者自己运用指正,只要把下面这几点牢记于心,就应该没问题,一步一步去拆解理解:
  • type *ptr:type类型的指针,名为ptr
  • *ptr:ptr所指向位置的值
  • *(ptr + i):ptr所指向位置加上i)的值
  • &thing:thing的地址
  • type *ptr = &thing:名为ptr,type类型的指针,值设置为thing的地址
  • ptr++:自增ptr指向的位置*

结构体

从一段代码搞起:

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
//使用strdup来复制字符串name,是为了确保结构体真正拥有它。strdup的行为实际上类似malloc但是它同时会将原来的字符串复制到新创建的内存。
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who->name);
free(who);
}
void Person_print(struct Person *who)
{
printf("Name: %s\n", who->name);
printf("\tAge: %d\n", who->age);
printf("\tHeight: %d\n", who->height);
printf("\tWeight: %d\n", who->weight);
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person *joe = Person_create(
"Joe Alex", 32, 64, 140);
struct Person *frank = Person_create(
"Frank Blank", 20, 72, 180);
// print them out and where they are in memory
printf("Joe is at memory location %p:\n", joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", frank);
Person_print(frank);
// make everyone age 20 years and print them again
joe->age += 20;
joe->height -= 2;
joe->weight += 40;
Person_print(joe);
frank->age += 20;
frank->weight += 20;
Person_print(frank);
// destroy them both so we clean up
Person_destroy(joe);
Person_destroy(frank);
return 0;
}

其实结构体就相当于数据库中的一行或者OOP语言中的类一样*

##