-
字符型数组的定义和初始化
char s[] = "hello";
:在栈上开辟空间并初始化。const char *p = "hello";
:指针p
指向字符串常量区的 "hello",只能读取不能修改。
-
指针变量的类型确定
- 指针变量的类型由其所指向的数据的类型决定。
- 例如,
char *
指向字符型数据,int *
指向整型数据。
-
处理字符串的方式
- 直接定义字符数组存储字符串。
- 使用指针指向字符串常量。
-
const
关键字
在指针操作一维字符型数组时,将形参设计为 const char *
具有重要的意义和好处。其目的在于防止函数内部对传入的字符指针所指向的内容进行误操作,增强程序的安全性和稳定性。
好处主要体现在以下几个方面:
- 能够将可能在运行时出现的问题提前到编译时发现。例如,如果在函数内部试图修改被声明为
const
的字符指针所指向的内容,编译器会报错,从而提前避免潜在的错误。 const char *
这种类型的形参具有很强的通用性,可以接收char *
类型和const char *
类型的实参。实参可以是数组名、指针变量(char *p
或const char *p
),也可以是直接的字符串常量。这极大地提高了参数的适用性。
不同的指针声明方式:
const char *s
和char const *s
表示所指向的字符内容是只读的,不能通过*s
来修改其指向的字符内容。char * const s
表示指针s
本身是只读的,不能指向其他的地址。
const
限定基类型的情况:
const int *p = &a
和int const *p = &a
表示不能通过*p
的方式修改a
的值。int * const p = &a
表示指针p
不能被修改,即不能指向其他变量。
在实际应用中:
- 如果不想通过
*p
的方式改变基类型对应的数据,可以使用const int *p = &a
或int const *p = &a
。 - 如果指针变量
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;
}