目录
前言
指针,指向的不仅仅是内存还有程序员的门槛!通过它的指引,我们可以一步一步揭开程序员神秘的面纱!
正文:习题15
代码
1 #include <stdio.h>
2
3 int main(int argc, char *argv[])
4 {
5 //随便整两个常用数组
6 int ages[] = {23, 43, 12, 89, 2};
7 char *names[] = {"Alen", "Frank", "Mary", "Jack", "Lisa"};
8
9 //safely get the size of ages安全的获取数组大小?
10 int count = sizeof(ages) / sizeof(int);
11 int i = 0;
12
13 //首先用索引方式获取数据
14 for(i = 0; i < count; i++){
15 printf("%s has %d years alive.\n", names[i], ages[i]);
16 }
17
18 printf("---\n");
19
20 //将指针指向ages数组的起始位置
21 int *cur_age = ages;
22 char **cur_name = names;
23
24 //然后用指针
25 for(i = 0; i <count; i++) {
26 printf("%s is %d years old.\n", *(cur_name + i), *(cur_age + i));
27 }
28
29 printf("---\n");
30
31 //其次,指针当数组用
32 for(i = 0; i < count; i++) {
33 printf("%s is %d years old again.\n", cur_name[i], cur_age[i]);
34
35 }
36
37 printf("---\n");
38
39 //最后愚蠢的使用指针
40 for(cur_name = names, cur_age = ages; (cur_age - ages) < count; cur_name++, cur_age++){
41
43 printf("line%d>>%s lived %d years so far. cur_name:%p,names:%p,cur_age:%p,ages:%p\n", __LINE__,*cur_name, *cur_age,cur_name, names, cur_age, ages);
44
46 }
47
48 return 0;
49 }
50
此次代码增加了行好还有一些中文的蹩脚翻译及注释,恩还加了41、43、44这三行代码。
输出
解释指针
原文巴拉巴拉的讲了很多。
部分摘抄如下:
指针是一个具有明确类型的指向计算机内存的地址。
指针与数组可以用很多一样的方法操作它们。比如对指针,可以用数组语法访问它。对数组,可以进行指针运算。所以大部分情况下,最好使用数组。
不过指针与数组不一样。
它们大小不一样。
指针更趋近于数组加索引(ages+i)。
指针可以对内存块进行原始、直接的访问。(很牛叉吗?体现在哪?)
指针的优越性:
指针直接访问内存的优越性主要体现在以下几个方面:
快速访问:通过指针直接访问内存可以绕过一些额外的操作,减少了访问内存的时间消耗。相比于通过变量名访问内存,指针直接访问内存可以提高程序的执行效率。
灵活性:指针可以指向任意类型的数据,通过指针可以在不同的上下文中访问和操作内存。这使得指针可以灵活地处理复杂的数据结构和算法。
动态内存管理:通过指针可以动态分配和释放内存。这使得程序可以根据需要在运行时动态地管理内存,提高内存利用率和程序的灵活性。
数据共享和传递:通过指针可以在不同的函数或模块之间共享和传递数据。指针可以传递地址而不是数据本身,这样可以避免数据的复制操作,提高了数据传递的效率。
然而,指针直接访问内存也存在一些潜在的问题和风险,如空指针、野指针等问题,需要程序员对指针的使用进行严格的控制和管理,避免出现内存错误导致的程序崩溃或安全漏洞。
对于指针的优越性,留待以后搞算法时再细细品它。(纸上得来终觉浅,觉知此事要躬行!)
指针用途
向系统请求一块内存,使用指针来处理它。这包括字符串,以及你还没见过的struct。(其实我已经见过) |
利用指针指向函数传递一大块内存(如巨大的struct), 这样就不必传递一份完整的数据了。 |
取得函数地址,可以动态回调。 |
扫描复杂的内存区域,将网络套接字中的字节转换成数据结构,或者语法分析文件。 |
其它解释加实例:
1、内存管理:指针可以用于动态分配和释放内存,通过动态分配内存,我们可以灵活地创建和操作数据结构,如动态数组、链表等。
举例:使用指针动态分配内存创建一个动态数组。
int size; printf("请输入数组大小:"); scanf("%d", &size); int* arr = malloc(size * sizeof(int)); if(arr == NULL) { printf("内存分配失败!\n"); return 0; } // 使用动态数组进行操作... free(arr); // 释放内存
2、传递参数:指针允许我们通过引用传递参数,传递指针可以避免复制大对象,提高程序的性能。
举例:使用指针传递参数给函数。
void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } int main() { int x = 5, y = 10; swap(&x, &y); printf("x=%d, y=%d\n", x, y); return 0; }
3、字符串处理:指针可以用于对字符串进行操作,如复制、连接、查找等。
举例:使用指针复制字符串。
char* str_copy(const char* src) { char* dest = malloc(strlen(src) + 1); if(dest == NULL) { printf("内存分配失败!\n"); return NULL; } strcpy(dest, src); return dest; } int main() { char* str = "Hello, World!"; char* copy = str_copy(str); printf("复制结果:%s\n", copy); free(copy); // 释放内存 return 0; }
4、数据结构操作:指针在数据结构中经常被使用,如链表、树等结构,通过指针可以方便地访问和操作数据。
举例:使用指针操作链表。
typedef struct Node { int data; struct Node* next; } Node; Node* create_node(int data) { Node* newNode = malloc(sizeof(Node)); if(newNode == NULL) { printf("内存分配失败!\n"); return NULL; } newNode->data = data; newNode->next = NULL; return newNode; } void insert_node(Node** head, int data) { Node* newNode = create_node(data); if(*head == NULL) { *head = newNode; } else { newNode->next = *head; *head = newNode; } } void print_list(Node* head) { Node* current = head; while(current != NULL) { printf("%d ", current->data); current = current->next; } printf("\n"); } int main() { Node* head = NULL; insert_node(&head, 1); insert_node(&head, 2); insert_node(&head, 3); print_list(head); return 0; }
这些只是指针的一些常见用途和举例,指针在编程中还有很多其他用途,如函数指针、动态多态性等。
还是不懂的话,就纸上什么觉知什么了!
指针词汇表
type *ptr: | 一个叫ptr的type类型指针 |
*ptr | ptr所指向的地址的值 |
*(ptr + i) | ptr所指向的地址加i的位置的值 |
&thing | thing的地址 |
type *ptr = &thing | 把叫做ptr的type类型的指针设置为thing的地址 |
ptr++ | 自增ptr指向的位置 |
黄色三个本以为是没问题的,但是到了算法时,也刺挠了一下。
不破不立
1、尝试将cur_age指向names。 (需要研究一下cast)
cur_age =(int *) names;
printf("cur_age:%d \n", cur_age[0]);
不报错之后的输出:(
2、在最后一个for循环中,尝试用各种方法让计算出错。(这最后一个循环我每次都要花不少时间去玩它,不理解就用print打印出来.)
3、尝试重写这些循环,从结尾向开头访问数组。看着简单,其实很难。(我看这是附加任务吧!)
还真的很难,最后我也很庆幸就改一个,你也可以先自己改一下再看下面的答案。
#include <stdio.h>
int main(int argc, char *argv[])
{
//随便整两个常用数组
int ages[] = {23, 43, 12, 89, 2};
char *names[] = {"Alen", "Frank", "Mary", "Jack", "Lisa"};
//safely get the size of ages安全的获取数组大小?
int count = sizeof(ages) / sizeof(int);
int i = 0 ;
printf("count:%d, i:%d\n:", count, i);
//首先用索引方式获取数据
for(i = count-1; i > 0; --i){
printf("count:%d, i:%d\n:", count, i);
printf("%s has %d years alive.\n", names[i], ages[i]);
}
printf("---\n");
return 0;
}
附加任务
1 | 将这个程序中的所有数组重写为指针。 |
2 | 将这个程序中的所有指针重写为数组。 |
3 | 只用指针处理命令行参数, 方法与本例中处理names相似。 |
4 | 尝试将获取地址与获取值结合起来使用。 |
5 | 在结尾加入另一个for循环,打印这些指针的地址(上面的破坏2已做)。 |
6 | 重写这个程序,使每种打印方式使用一个函数。尝试将指针传递给函数以便它们获取数据。你可以声明一个函数接受指针作为参数,但这个参数也可以当做数组使用。 |
7 | 将for循环改为while,看看对于不同种类的指针使用,哪种循环更为适用。 |
1、2、3、4不太理解题目意思抑或是修行尚浅,就跳过了。大家如果知道答案,欢迎大家评论区留言,谢谢!
5在破坏里做了。
6很重要,前期不会后期挺难受。
6的代码:
1 #include <stdio.h>
2
3 void print_a(int count, int *nianling, char **mingzi );
4 int print_b(int c, int *nian, char **ming);
5 char print_c(int c, char **m, int *n);
6
7 void print_d(char **m, int *n, int c )
8 {
9 int *cur_age;
10 char **cur_name;
11 for(cur_name = m, cur_age = n; (cur_age - n) < c; cur_name++, cur_age++){
12 printf("line%d>>%s lived %d years so far. \n", __LINE__,*cur_name, *cur_age);
13
14 }
15
16 }
17
18 int main(int argc, char *argv[])
19 {
20 int ages[] = {23, 43, 12, 89, 2};
21 char *names[] = {"Alen", "Frank", "Mary", "Jack", "Lisa"};
22
23 int count = sizeof(ages) / sizeof(int);
24
25 print_a(count, ages, names);
26 print_b(count, ages, names);
27 print_c(count, names, ages);
28 print_d(names, ages, count);
29
30 return 0;
31 }
32
33 void print_a(int count, int *nianling, char **mingzi){
34 int i = 0;
35
36 for(i = 0; i < count; i++){
37 printf("%s has %d years alive.\n", mingzi[i], nianling[i]);
"ex0055.c" 64L, 1244B 已写入 2,0-1 顶端
38 }
39
40 printf("---\n");
41 }
42
43 int print_b(int c, int *nian, char **ming){
44 for(int i = 0; i <c; i++) {
45 printf("%s is %d years old.\n", *(ming + i), *(nian + i));
46 }
47
48 printf("---\n");
49
50 return 0;
51 }
52
53 char print_c(int c, char **m, int *n)
54 {
55 for(int i = 0; i < c; i++) {
56 printf("%s is %d years old again.\n", m[i], n[i]);
57
58 }
59
60 printf("---\n");
61 char bala = 'b';
62 return bala;
63 }
64/
/在一通胡乱尝试后,对于函数及函数传参啥的,我的理解又更进一层了,呵呵!你们看明白我的瞎操了吗?
7、for与while,应该要多用吧!试过才知道,for的确很省事!
改一个就够了,顺便说下“断错误(核心已存储)”,曾经难死我了,现在也就是轻轻一个小迈步,嘎嘎!
后语
cast的解惑
在C语言中,cast是一种强制转换的操作符,它用于将一个数据类型转换为另一个数据类型。通过 cast,可以改变数据的类型,使其适合于特定的操作或表达式。
cast的一般语法如下:
(要转换的数据类型) 要转换的值
例如,要将一个整数转换为浮点数,可以使用以下语法:
int num = 10; float floatNum = (float) num;
在上述例子中,将整数num转换为浮点数floatNum。通过在要转换的数据类型前加上括号,就可以实现强制转换。注意,强制转换可能导致数据的丢失或截断,因此需要谨慎使用。
此外,还可以将指针类型进行强制转换。例如,将一个整数转换为指向整数的指针:
int num = 10; int* ptr = (int*) #
在上述例子中,将整数num的地址强制转换为指向整数的指针ptr。注意,这种指针类型的转换通常需要谨慎使用,因为可能导致不确定或不安全的行为。
需要注意的是,强制转换并不能改变数据本身的值,只是改变了数据的类型。因此,在使用强制转换时,需要确保转换后的数据类型能够正确处理转换后的值,以避免出现错误或意外的结果。
- 指针真的很难吗?乍一看,指针、指针……不就是指向一个东西的针吗?然而再多看看,就应对了一句话“欲练此功,必先自宫”(大神们别见外,要怪就怪绣花针吧!与我无瓜,哈哈!)
- 当然,神功还有十年磨一剑的坚持!只要它没打倒我,那它终将被我折服!爱好抑或兴趣是铁杵磨成针的动力!