嵌入式学习之路 15(C语言基础学习——指针操作一维字符型数组)

  1. 字符型数组的定义和初始化

    • char s[] = "hello";:在栈上开辟空间并初始化。
    • const char *p = "hello";:指针 p 指向字符串常量区的 "hello",只能读取不能修改。
  2. 指针变量的类型确定

    • 指针变量的类型由其所指向的数据的类型决定。
    • 例如,char * 指向字符型数据,int * 指向整型数据。
  3. 处理字符串的方式

    • 直接定义字符数组存储字符串。
    • 使用指针指向字符串常量。
  4. const 关键字

在指针操作一维字符型数组时,将形参设计为 const char * 具有重要的意义和好处。其目的在于防止函数内部对传入的字符指针所指向的内容进行误操作,增强程序的安全性和稳定性。

好处主要体现在以下几个方面:

  1. 能够将可能在运行时出现的问题提前到编译时发现。例如,如果在函数内部试图修改被声明为 const 的字符指针所指向的内容,编译器会报错,从而提前避免潜在的错误。
  2. const char * 这种类型的形参具有很强的通用性,可以接收 char * 类型和 const char * 类型的实参。实参可以是数组名、指针变量(char *pconst char *p),也可以是直接的字符串常量。这极大地提高了参数的适用性。

不同的指针声明方式:

  1. const char *schar const *s 表示所指向的字符内容是只读的,不能通过 *s 来修改其指向的字符内容。
  2. char * const s 表示指针 s 本身是只读的,不能指向其他的地址。

const 限定基类型的情况:

  1. const int *p = &aint const *p = &a 表示不能通过 *p 的方式修改 a 的值。
  2. int * const p = &a 表示指针 p 不能被修改,即不能指向其他变量。

在实际应用中:

  1. 如果不想通过 *p 的方式改变基类型对应的数据,可以使用 const int *p = &aint const *p = &a
  2. 如果指针变量 p 定义好后不想再指向别的变量,则使用 int * const p = &a

对于指针和字符串的关系,在 C 语言中字符串通常以字符数组的形式存储。例如 char s[] = "hello"; 是在栈上开辟一块空间,并使用字符串常量 "hello" 进行初始化。而 const char *p = "hello"; 表示 p 指向了字符串常量区中的 "hello" ,由于是指向字符串常量区,所以只能进行读取操作,不能对其进行修改。

例如,如果尝试这样修改:

cpp 复制代码
const char *p = "hello";
*p = 'H';  // 这会导致编译错误,因为不能修改字符串常量区的内容

而对于 char s[] = "hello"; 则可以进行修改:

cpp 复制代码
char s[] = "hello";
s[0] = 'H';  // 这是合法的修改

练习:用指针操作的方式实现系统函数的功能

gets

puts

strlen

strcpy /strncpy

strcat /strncat

strcmp /strncmp

cpp 复制代码
#include <stdio.h>
#include <string.h>

// 从标准输入获取字符串并存储到指定字符数组
char * Gets(char *s)
{
    char *ret = s;

    while ( (*s = getchar())!= '\n' )
    {
        s++;
    }
    *s = '\0';

    return ret;
}

// 输出字符串
int Pust(const char *s)
{
    while ( *s!= '\0' )
    {
        putchar(*s);
        s++;
    }
    printf("\n");

    return 0;
}

// 计算字符串长度
size_t Strlen(const char *s)
{
    const char *ret = s;
    while ( *s!= '\0')
    {
        s++;
    }

    return s - ret;
}

// 连接两个字符串
char *Strcat(char *dest, const char *src)
{
    char *ret = dest;

    while ( *dest!= '\0' )
        dest++;

    while ( *src!= '\0' )
    {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';

    return ret;
}

// 连接指定长度的两个字符串
char *Strncat(char *dest, const char *src, size_t n)
{
    char *ret = dest;

    while ( *dest!= '\0' )
        dest++;

    while ( *src!= '\0' && n )
    {
        *dest = *src;
        dest++;
        src++;
        n--;
    }
    *dest = '\0';

    return ret;
}

// 复制字符串
char * Strcpy(char *dest, char *src)
{
    char *ret = dest;

    while( *src!= '\0' )
    {
        *dest = *src;
        dest++;
        src++;
    }
    *dest = '\0';

    return ret;
}

// 复制指定长度的字符串
char * Strncpy(char *dest, char *src, size_t n)
{
    char *ret = dest;

    while( *src!= '\0' && n!= 0 )
    {
        *dest = *src;
        dest++;
        src++;
        n--;
    }

    while ( n )
    {
        *dest = '\0';
        *dest++;
        n--;
    }

    return ret;
}

// 比较两个字符串
int Strcmp(const char *dest, const char *src)
{
    while ( *dest == *src && *dest!= '\0' && *src!= '\0' )
    {
        dest++;
        src++;
    }

    return *dest - *src;
}

// 比较指定长度的两个字符串
int Strncmp(const char *dest, const char *src, size_t n)
{
    while ( *dest == *src && *dest!= '\0' && *src!= '\0' && n > 1 )
    {
        dest++;
        src++;
        n--;
    }

    return *dest - *src;
}

// 主函数,用于测试上述函数
int main()
{
    // 定义并初始化字符数组 a
    char a[20];
    // 调用 Gets 函数获取用户输入并存储到 a 中
    Gets(a);

    char s[100];
    // 调用 Gets 函数获取用户输入并存储到 s 中
    Gets(s);

    // 调用 Strncmp 函数比较 a 和 s 的前 3 个字符,并输出结果
    printf("%d\n", Strncmp(a, s, 3));

    return 0;
}
相关推荐
Cons.W1 小时前
Codeforces Round 975 (Div. 1) C. Tree Pruning
c语言·开发语言·剪枝
我是哈哈hh1 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
Ace'1 小时前
每日一题&&学习笔记
笔记·学习
Tisfy1 小时前
LeetCode 2187.完成旅途的最少时间:二分查找
算法·leetcode·二分查找·题解·二分
IM_DALLA1 小时前
【Verilog学习日常】—牛客网刷题—Verilog进阶挑战—VL25
学习·fpga开发·verilog学习
挥剑决浮云 -1 小时前
Linux 之 安装软件、GCC编译器、Linux 操作系统基础
linux·服务器·c语言·c++·经验分享·笔记
Mephisto.java1 小时前
【力扣 | SQL题 | 每日四题】力扣2082, 2084, 2072, 2112, 180
sql·算法·leetcode
robin_suli1 小时前
滑动窗口->dd爱框框
算法
丶Darling.1 小时前
LeetCode Hot100 | Day1 | 二叉树:二叉树的直径
数据结构·c++·学习·算法·leetcode·二叉树