一起笨笨的学C——005指针

 

目录

前言

正文:习题15

代码

输出

​编辑

 解释指针

指针用途       

指针词汇表

不破不立

附加任务

后语

        A:cast


 

前言

        指针,指向的不仅仅是内存还有程序员的门槛!通过它的指引,我们可以一步一步揭开程序员神秘的面纱!

      


 

正文:习题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这三行代码。

 

输出

d790d1c14ba24a2d8f2aee19847adace.png

 

 解释指针

        原文巴拉巴拉的讲了很多。

        部分摘抄如下:

        指针是一个具有明确类型的指向计算机内存的地址。

        指针与数组可以用很多一样的方法操作它们。比如对指针,可以用数组语法访问它。对数组,可以进行指针运算。所以大部分情况下,最好使用数组。

        不过指针与数组不一样。

        它们大小不一样。

        指针更趋近于数组加索引(ages+i)。

        指针可以对内存块进行原始、直接的访问。(很牛叉吗?体现在哪?)

        指针的优越性:

指针直接访问内存的优越性主要体现在以下几个方面:

  1. 快速访问:通过指针直接访问内存可以绕过一些额外的操作,减少了访问内存的时间消耗。相比于通过变量名访问内存,指针直接访问内存可以提高程序的执行效率。

  2. 灵活性:指针可以指向任意类型的数据,通过指针可以在不同的上下文中访问和操作内存。这使得指针可以灵活地处理复杂的数据结构和算法。

  3. 动态内存管理:通过指针可以动态分配和释放内存。这使得程序可以根据需要在运行时动态地管理内存,提高内存利用率和程序的灵活性。

  4. 数据共享和传递:通过指针可以在不同的函数或模块之间共享和传递数据。指针可以传递地址而不是数据本身,这样可以避免数据的复制操作,提高了数据传递的效率。

然而,指针直接访问内存也存在一些潜在的问题和风险,如空指针、野指针等问题,需要程序员对指针的使用进行严格的控制和管理,避免出现内存错误导致的程序崩溃或安全漏洞。

        对于指针的优越性,留待以后搞算法时再细细品它。(纸上得来终觉浅,觉知此事要躬行!)

 

指针用途       

主要用途
向系统请求一块内存,使用指针来处理它。这包括字符串,以及你还没见过的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类型指针
*ptrptr所指向的地址的值
*(ptr + i)ptr所指向的地址加i的位置的值
&thingthing的地址
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]);

 

        不报错之后的输出:(

79cb9acefa9a4bf59ec5a81f71525e1d.png      

   2、在最后一个for循环中,尝试用各种方法让计算出错。(这最后一个循环我每次都要花不少时间去玩它,不理解就用print打印出来.)

7fd3246a725d4ca7a4958e44f524a6ff.png

9f2758ce80234430a6cd6b59e04cf576.png       

          3、尝试重写这些循环,从结尾向开头访问数组。看着简单,其实很难。(我看这是附加任务吧!)

        2b3fb74d1f934ee2b97c725d2a5ccccf.png

 还真的很难,最后我也很庆幸就改一个,你也可以先自己改一下再看下面的答案。

#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的确很省事!

64e3ee9892d34dbea85d9fae4fa31774.png

 改一个就够了,顺便说下“断错误(核心已存储)”,曾经难死我了,现在也就是轻轻一个小迈步,嘎嘎!


后语

        cast的解惑

        

在C语言中,cast是一种强制转换的操作符,它用于将一个数据类型转换为另一个数据类型。通过 cast,可以改变数据的类型,使其适合于特定的操作或表达式。

cast的一般语法如下:

(要转换的数据类型) 要转换的值

例如,要将一个整数转换为浮点数,可以使用以下语法:

int num = 10; float floatNum = (float) num;

在上述例子中,将整数num转换为浮点数floatNum。通过在要转换的数据类型前加上括号,就可以实现强制转换。注意,强制转换可能导致数据的丢失或截断,因此需要谨慎使用。

此外,还可以将指针类型进行强制转换。例如,将一个整数转换为指向整数的指针:

int num = 10; int* ptr = (int*) #

在上述例子中,将整数num的地址强制转换为指向整数的指针ptr。注意,这种指针类型的转换通常需要谨慎使用,因为可能导致不确定或不安全的行为。

需要注意的是,强制转换并不能改变数据本身的值,只是改变了数据的类型。因此,在使用强制转换时,需要确保转换后的数据类型能够正确处理转换后的值,以避免出现错误或意外的结果。

 

  1. 指针真的很难吗?乍一看,指针、指针……不就是指向一个东西的针吗?然而再多看看,就应对了一句话“欲练此功,必先自宫”(大神们别见外,要怪就怪绣花针吧!与我无瓜,哈哈!)
  2. 当然,神功还有十年磨一剑的坚持!只要它没打倒我,那它终将被我折服!爱好抑或兴趣是铁杵磨成针的动力!

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值