字符数组、指针
拓展:
在VIM里快速进入man手册:先Esc退出 --> 光标到对应的函数 -->shift + q 进入
unlimited:查询资源占用情况
自查string手册里的所有相关函数
一、字符数组
1、字符数组的定义初始化
字符数组也允许在定义时作初始化赋值
定义方式:
char c[10]={'c', ' ', 'p', 'r','o', 'g', 'r', 'a','m'};
char str[] = "abcdb11111";
char str1[] = "abcda11111";
输出方式:
char c[ ] = "I am happy";
printf("%c", c[i]); //逐个字符输出。
char c[ ] = "I am happy";
printf("%s", c); //将整个字符串一次输出 必须得是字符数组名
puts(c); //对字符串进行输出时可以用puts字符串常量后面一定有一个''\0'
在 C 语言中,字符串总是以’\0’作为结尾,所以’\0’也被称为字符串结束标志,或者字符串结束符
单个字符进行输出是不能用puts puts输出时必须用’\0’来进行结束标记
puts
对字符串进行输出时可以用puts(字符串常量后面一定有一个’’\0’)
char sstr[] = “hello”;
puts(sstr);
2、字符数组相关函数
strlen:
作用:用来计算指定的字符串s 的长度,不包括结束字符"\0"。
返回值:返回字符串s 的字符数。
strlen() 函数计算的是字符串的实际长度,遇到第一个'\0'结束。如果你只定义没有给它赋初值,这个结果是不定的,它会从首地址一直找下去,直到遇到'\0'停止。而sizeof返回的是变量声明后所占的内存数,不是实际长度,此外sizeof不是函数,仅仅是一个操作符,strlen()是函数。
char str3[] = "12345"; //strlen(str3)=5, sizeof(str3)=6
char str3[] = "12\0t45"; //strlen(str3)=2, sizeof(str3)=7
char str3[10] = "12t45"; //strlen(str3)=5, sizeof(str3)=10
strcpy/strncpy:
作用:字符串复制strcpy把从src地址开始且含有’\0’结束符的字符串复制到以dest开始的地址空间
返回值类型:目标串的地址char*
函数原型:char* strcpy(char* des,const char* src) //des为目标字符串,source为原字符串
char str[32] = "hello";
char str1[12];
printf("str = %p\n",str);
printf("str1 = %p\n",str1);
strcpy(str1, str); //将str复制到str1
puts(str);
puts(str1);
strncpy:将源字符串中最多count个字符复制到目的字符串中,返回指向目的字符串的指针。
//原型
char *strncpy(char *dest, char *src, int n);
//如果src的前n个字节不含NULL字符,则结果不会以NULL字符结束。
//strncpy总是复制 n 个字符到dst指向的内存
//如果src的长度小于n个字节,则以NULL填充dest直到复制完n个字节。
//src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
strcat/strncat:
作用:把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
返回值:该函数返回一个指向最终的目标字符串 dest 的指针
函数原型:char *strcat(char *dest, const char *src)
char str[128];
char h[] = "hello",s[] = " ",w[] = "world";
strcpy(str,h);
strcat(str,s);
strcat(str,w);
puts(str);
**strncat:**如果str2的字符数大于n,那么该函数只将str2的前n个字符附加在str1末尾,如果str2中的字符数小于n,该字符会将str2的所有字符附加在str1末尾。
//原型
char * strncat(char *str1,const *char *str2,size_t_n);
//无论哪种情况,都会在新字符串的末尾添加空字符。必须为str1分配足够的空间以存储新的字符串。strncat()函数返回指向str1的指针。
strcmp/strncmp:串比较
作用:比较字符串,比较的时候逐个字符比较
函数原型:int strcmp(const char *str1, const char *str2)
如果str1>str2,返回>0;
如果str1<str2,返回<0;
如果str1=str2,返回=0;
//在具体实现过程中,我们需要遍历两个字符串,直到其中一个字符串结束,每一次循环都要比较两个字符串中字符大小
char str[] = "abcdb11111";
char str1[] = "abcda11111";
printf("%d\n",strcmp(str1,str)); //相当于str-str1 输出:-1
printf("%d\n",strncmp(str1,str,7)); //将str和str1的前7个字符进行比较 输出-1
strncmp:此函数功能即比较字符串str1和str2的前maxlen个字符
//原型
int strncmp(char *str1, char *str2, int maxlen);
//如果前maxlen字节完全相等,返回值就=0;在前maxlen字节比较过程中,如果出现str1[n]与str2[n]不等,则返回(str1[n]-str2[n])
3、习题
输入一行字符,统计其中单词个数。(该问题主要练习标志位的使用,另外如果该问题用字符来进行实现的话会走很多弯路,用字符串进行逐个字符的遍历较方便一些)
#include <stdio.h>
#include <stdlib.h>
//hello world 123 456
int main()
{
char buf[128];
int i = 0,count = 0,flag = 0;
gets(buf);
for(; buf[i] != '\0'; i++)
{
if(buf[i] == ' ')
{
flag = 0;
}
else // char
{
if(flag == 0)
{
flag = 1;
count++;
}
}
}
printf("WORD:%d\n",count);
exit(0);
}
二、指针
只要是指针类型就占8个字节
**变量:**是给人看的,抽象命名
**地址:**就是变量所在位置,指针。
1、指针的基本概念
指针的作用: 可以通过指针间接访问内存
- 内存编号是从0开始记录的,一般用十六进制数字表示
- 可以利用指针变量保存地址
2、指针变量的定义和使用
指针变量定义语法: 数据类型 * 变量名;
指针变量和普通变量的区别
- 普通变量存放的是数据,指针变量存放的是地址
- 指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用
程序实现:
int main()
{
int i = 1; //指针大小默认8个字节
int* p = &i; //一级指针 p的类型是int* p是用来保存地址的变量 用来存放指针的变量
int** q = &p; //二级指针不能存放整型数的地址
printf(" i ---> %d\n",i);
printf(" &i ---> %p\n\n",&i);
printf(" p ---> %p &i ---> %p\n",p,&i);
printf(" &p ---> %p\n",&p);
printf(" *p ---> %d i ---> %d\n\n",*p,i);
printf(" q ---> %p\n",&p);
printf(" &q ---> %p\n",&p);
printf(" *q ---> %p p ---> %p\n",*q,p);
printf(" **q ---> %d i ---> %d\n",**q,i);
exit(0);
}
输出:
总结
我们可以通过 & 符号 获取变量的地址
利用指针可以记录地址
对指针变量解引用,可以操作指针指向的内存
直接访问、间接访问
3、空指针和空类型
空指针:针变量指向内存中编号为0的空间(指针的值为空,能有效避免野指针的产生。
用途:初始化指针变量。
注意:空指针指向的内存是不可以访问的
int main()
{
int i = 1;
int *p = &i;
void *m = NULL;
*p = 100;
printf("%d\n",*p);
exit(0);
}
输出:100
空类型:void *m =NULL; 可以接受任何类型的指针值(16:39)
void* 类型不能坐取*运算,用来传参和返回值。
空类型的指针不能存放值
4、野指针
野指针:指针变量指向非法的内存空间,仍然在访问,指针的指向不明确。