&
是取地址符号 是升
纬度的
*
是取值符号 是降维
度的
指针就是内存中的一个地址编号,指针变量用于存储地址,指针变量也是一个变量。
#include
int main(void) {
int a = 0xaabbccdd;
printf("%p\n", &a);//获取a的内存地址
return 0;
}
内存中的每一个数据都会分配相应的地址
char 占内存一
个字节
,分配一
个地址
int 占内存四
个字节
,分配四
个地址
windows电脑在做数据存储时采用小端对齐(低位数据
放在低位内存地址
,高位数据
放在高位内存地址
)。
大端对齐:低位数据放在高位内存地址,高位数据放在低位内存地址。
计算机的字节顺序模式分为大端数据模式和小端数据模式,它们是根据数据在内存中的存储方式来区分的。小端对齐和大端对齐都是计算机中数据存储的一种方式。
数据类型* 变量名
定义指针类型变量
*变量名 = 值通过指针间接修改变量的值
#include
int main(void) {
int a = 0;
printf("%p\n", &a);//获取a的内存地址
//定义指针变量存储变量地址
int* b = &a;
printf("%p\n", b);
*b = 20;//通过指针间接修改变量的值
printf("%d\n", a);
printf("%d\n", *b);
return 0;
}
结果:
0000004CCAAFF874
0000004CCAAFF874
20
20
指针间接赋值
- 两个变量:普通变量、指针变量
- 建立关系 指针变量=&普通变量
- 通过 *运算符赋值 *指针变量=值
int main(void) {
int a = 0;
int* b = &a;
printf("%d\n", sizeof(a));//4
printf("%d\n", sizeof(b));//64位打印的是8,32位打印的是4
return 0;
}
所有的指针类型存储的都是内存地址,内存地址都是一个无符号16进制整型数。
64位操作系统下所有指针类型是8个字节大小,32位操作系统下所有指针类型是4个字节大小。所有的指针类型占的字节大小都一样
int main(void) {
printf("%d\n", sizeof(int*));
printf("%d\n", sizeof(char*));
printf("%d\n", sizeof(short*));
printf("%d\n", sizeof(long*));
printf("%d\n", sizeof(float*));
printf("%d\n", sizeof(double*));
return 0;
}
既然地址是无符号类型的整型数(unsigned int),我们定义一个整型int
不行吗?为什么要用int*
?
int main(void) {
int a = 0;
int b = &a;
//*b = 666;//err: b不是指针类型,而是一个整型
*(int*)b = 666;//强制类型转换,把一个普通变量转成int*类型
printf("%d\n", a);//666
return 0;
}
既然char* 占4字节大小,int* 也是占4个字节大小,我可以都用int* 不用char*吗?
#include
int main(void) {
char c = 'a';
int* b = &c;
printf("%p\n", b);//007AFDD3
printf("%p\n", &c);//007AFDD3
printf("%d\n", c);//97
printf("%d\n", *b);//-858993567
return 0;
}
野指针:指针变量指向一个未知(内存)的空间。
#include
int main() {
// 野指针
int* b = 100;
printf("%d\n,",*b);//可能会err: 操作野指针对应的内存空间可能报错
return 0;
}
可以看到报错了:引发了异常: 读取访问权限冲突。为什么?操作系统将0-255
作为系统占用不允许读写
操作。
程序中允许出现野指针,但是操作野指针对应的内存空间可能报错
,有几个问题,1. 这块内存地址允不允许访问;2. 这里有没有数据;3. 这数据能不能修改 。
指针变量也是变量,是变量就可以任意赋值,不要越界即可(32位为4字节,
64位为8字节),但是,任意数值赋值给指针变量没有意义,因为这样的指针
就成了野指针,此指针指向的区域是未知(操作系统不允许操作此指针指向的
内存区域)。所以,野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。在程序运行过程中,我们尽量不要把一个具体的值(或者变量的值)直接赋值给指针变量。
空指针:是指内存地址编号为0的空间。
野指针和有效指针变量保存的都是数值,为了标志此指针变量没有指向任何变量(空闲可用),c语言中,可以把NULL赋值给此指针,这样就标志此针为空指针,没有任何指针。
操作空指针对应的空间一定会报错,空指针可以用作条件判断
int main() {
int* b = NULL;
//*b = 666;//err: 引发了异常: 写入访问权限冲突。
//printf("%d\n", *b);//err: 引发了异常: 读取访问权限冲突。
if ( b == NULL ){
printf("这是空指针");
}
return 0;
}
NULL是一个值为0的宏常量:
#define NULL ((void *)0)
void*指针可以指向任意变量的内存空间,万能指针并不是真的万能,而是他能接收任意类型的数据,在通过万能指针修改变量的值时,需要转成变量对应的的指针类型。
万能指针可以直接赋值给其他类型的指针,其他类型指针赋值给万能指针的时候,最好强转一下类型才可以。
可以将所有指针类型赋值给万能指针 ,万能指针一般用作于函数形参。
#include
int main() {
printf("void*在内存中占的字节大小为: %d\n", sizeof(void*));//64位打印的是8,32位打印的是4
void* b = NULL;
int a = 10;
b = (void*)&a;//指向变量时,最好转换为void*
//*b = 87;//err: 非法的间接寻址 void本身不是数据类型
//printf("void在内存中占的字节大小为: %d\n", sizeof(void));//0 不允许使用不完整的类型
//使用指针变量指向的内存时,强转为int*
*(int*)b = 87;
printf("%d\n", a);//87
printf("%d\n", *(int*)b);//87
return 0;
}
普通
的常变量我们通过一级指针
修改
#include
int main() {
const int a = 123;
//a = 456;//err: 左值被const修饰了
printf("a修改前:%d\n", a);//123
//通过指针间接改变常量的值
int* b = &a;
*b = 456;
printf("a修改后:%d\n", a);//456
return 0;
}
可以通过指针修改const定义的常变量,但是不能修改#define定义的宏定义常量。为什么?#define
宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存
。(宏定义不分配内存,变量定义分配内存)。const常变量
会在内存中分配(可以是堆
中也可以是栈
中)。
#include
int main() {
int a = 10;
int b = 20;
const int* c = &a;
printf("a的地址:%p\n", &a);//006FF838
printf("b的地址:%p\n", &b);//006FF82C
printf("c修改前:%p\n", c);//006FF838 = a
c = &b;//无问题
printf("c修改后:%p\n", c);//006FF82C = b
return 0;
}
#include
int main() {
int a = 10;
int b = 20;
const int* c = &a;
c = &b;//ok:可以修改指针变量的值
//*c = 99;//err:不可以修改指针对应的内存空间的值
printf("%d\n", *c);
return 0;
}
const 修饰
指针类型
可以修改指针变量的值,不可以修改指针指向内存空间的值。这里的是指针对应的内存空间,指向常量的指针。
const int* c = &a;
c = &b;
PS:我们可以这样记, const 跟 * 近不能修改 * ,跟c近不能修改c,const相当于加锁一样,哪个加上锁哪个就不能修改了。
const 修饰
指针变量
可以修改指针指向内存空间的值,不可以修改指针变量的值。这里的c是指针变量。
int* const c = &a;
*c = 200;
int main() {
int a = 10;
int b = 20;
int* const c = &a;
//c = &b;//err
*c = 200;//ok
printf("%d\n", a);//200
return 0;
}
一级指针
常变量我们通过二级指针
来修改
const修饰指针类型 修饰指针变量
const int* const c = &a; 这里的c是只读指针
通过二级指针可以修改一级指针的值(相当于c),修改一级指针对应内存空间的值(*c)。同理,三级指针可以修改二级指针的值,可以依次往前扣。
#include
int main() {
int a = 10;
int b = 20;
//const修饰指针类型 修饰指针变量
const int* const c = &a;
printf("改变之前:%d\n", *c);//10
// c = &b;//err:表达式必须是可修改左值
// *c = 200;//err:表达式必须是可修改左值
int** cc = &c;
//1
// *cc = &b;//改变c的值
// printf("改变之后:%d\n", *c);//20
//2
**cc = 21;//改变*c的值
printf("改变之后:%d\n", *c);//21
return 0;
}
数组名字是数组的首元素地址,但它是一个常量。
int arr[] = { 1,2,3,4,5 };
printf("%p\n", arr);//0000009C47B4F988
printf("%p\n", &arr[0]);//0000009C47B4F988
#include
int main() {
int arr[] = { 1,2,3,4,5 };
int* p = arr;
for (int i = 0; i < 5; i++)
{
//printf("%d\n", arr[i]);//ok
//printf("%d\n", p[i]);//ok,与上面一样结果
/*
int*指针 指针类型+1等同于内存地址+sizeof(int)
*/
//printf("%d\n", *(arr+i));//ok,与上面一样结果
printf("%d\n", *(p+i));//ok,与上面一样结果
}
return 0;
}
指针类型+1 等同于 内存地址+sizeof(类型),这里面元素并不是以内存地址编号为单位的,单位都是具体类型为单位的。
#include
int main() {
int arr1[] = { 1,2,3,4,5 };//int占4个字节
int* p1 = arr1;
printf("%p\n", p1);//000000D9A22FF828
p1++;//p1=p1+1;
printf("%p\n", p1);//000000D9A22FF82C
char arr2[] = { 'W','X','H','Y' };//char占1个字节
char* p2 = arr2;
printf("%p\n", p2);//0000008CDE33F734
p2 = p2 + 1;
printf("%p\n", p2);//0000008CDE33F735
double arr3[] = { 1.23,5.2,6.3,5.5 };//double占8个字节
double* p3 = arr3;
printf("%p\n", p3);//000000F68AB3F7C8
p3 = p3 + 1;
printf("%p\n", p3);//000000F68AB3F7D0
return 0;
}
两指针相减,等到的结果是两个指针的偏移量(步长),所有的指针类型相减都是int类型。
指针+1 相当于 +sizeof(类型)
指针-1 相当于 -sizeof(类型)
指针相减 = 变量值(地址编号)相减/sizeof(类型)
int main() {
int arr1[] = { 1,2,3,4,5 };//int占4个字节
int* p1 = arr1;
printf("%p\n", p1);//00000086013BF8C8
p1++;
printf("%p\n", p1);//00000086013BF8CC
int step = p1 - arr1;//C8-CC=4 ,相当于 4/sizeof(int)=1
printf("步长:%d\n",step);//1
return 0;
}
数组作为函数参数会退化为指针,丢失了数组的精度(数组元素个数)
#include
//数组作为函数参数会退化为指针,丢失了数组的精度
void BubbleSort(int arr[5]) {//arr[] 或者 arr[100] 得到的结果都一样
int length = sizeof(arr)/sizeof(arr[0]);
printf("长度:%d\n", length);//1
printf("%d\n",sizeof(arr));//4
}
int main() {
int arr[5] = { 1,2,3,4,5 };
BubbleSort(arr);
return 0;
}
既然退化成指针了,我们可以写成int* arr,他们是等价的
#include
/* 冒泡排序 */
//数组作为函数参数会退化为指针,丢失了数组的精度
void BubbleSort(int* arr, int length) {
for (int i = 0; i < length - 1; i++)
{
for (int j = 0; j < length - 1 - i; j++)
{
/*if (arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}*/
if (*(arr + j) > *(arr + j + 1))
{
int temp = *(arr + j);
*(arr + j) = *(arr + j + 1);
*(arr + j + 1) = temp;
}
}
}
}
int main() {
int arr[6] = { 6,2,7,3,4,5 };
int length = sizeof(arr) / sizeof(arr[0]);
BubbleSort(arr, length);
for (int i = 0; i < length; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
结果:234567
如果我们指针去操作数组元素情况,最好写成数组样式,简单明了,一般情况不写指针样式。
指针运算跟指针类型对应的基本类型有关。
指针加减运算
(1)加法运算
#include
int main() {
int arr1[] = { 1,2,3,4,5 };//int占4个字节
int* p1 = arr1;
printf("%p\n", p1);//000000D9A22FF828
p1++;//p1=p1+1;
printf("%p\n", p1);//000000D9A22FF82C
return 0;
}
举个例子: 字符串拷贝的操作
1.通过数组操作
#include
//字符串拷贝的操作
void CopyStr(char* dest, char* ch) {
int i = 0;
//while (ch[i] != '\0')
//while (ch[i] != 0 )//等价于上一行
while (ch[i]) //等价于上一行
{
dest[i] = ch[i];
i++;
}
dest[i] = 0;//其实就是'\0'
}
int main(void) {
char ch[] = "hello world";
char dest[100];
CopyStr(dest, ch);
printf("%s\n", dest);
return 0;
}
2.指针加减运算
void CopyStr(char* dest, char* ch) {
int i = 0;
while (*(ch + i)) {
*(dest + i) = *(ch + i);//注意一定要加括号,因为优先级别的问题
i++;
}
*(dest + i) = 0;
}
3.把2再简化,还能这样写
void CopyStr(char* dest, char* ch) {
while (*ch) {
*dest = *ch;
dest++;//指针+1 相当于指向数组下一个元素 内存地址变化了sizeof(char)
ch++;
}
*dest = 0;
}
4.上面都还不是指针的最终版本,接下来我们再写个不一样的
void CopyStr(char* dest, char* ch) {
while (*dest++ = *ch++);
}
第一个算dest++、ch++,但其实是最后一个算的;然后是取值*dest、ch,接着给dest赋值;赋值完之后到这里表达式已经计算完成了,虽然++还没加但是表达式已经完成了,赋值完之后作为while循环的条件。
总的来说就是,第一步 取值*dest、*ch,第二步 *dest=*ch,第三步 把这个值作为条件判断,赋值哪个就是哪个进行判断,如果是0,这时候0已经赋值过去给*dest,不满足循环结束循环,最后一步 dest++、ch++。
(2)减法运算
#include
int main(void) {
int arr[] = { 1,2,3,4,5,6 };
int* p;
//arr[-1]//数组小标越界
p = &arr[3];
//指针操作数组时,下标允许是负数
printf("%d\n",p[-2]);//相当于*(p-2) ,结果2
printf("%p\n", arr);//0113FCC0
printf("%p\n", p);//0113FCCC 地址相差12个
int step = p - arr;// 12 / sizeof(int)=偏移量
printf("偏移量:%d\n",step);//3
p--;//指针的加减运算和指针的类型有关
p--;
p--;
printf("%p\n", p);//0113FCC0
return 0;
}
指针加减偏移量是允许的;减法可以减指针,但是没有意义
,此外还能用 > 、?、&& 等等
#include
int main(void) {
//指针和运算符的操作
int arr[] = {1,2,3,4,5,6,7,8};
int* p = &arr[3];
//野指针
//指针加减偏移量是允许的,但两个指针相加乘除是不允许的,取余也不行
//p = p + arr;//err: “ + ”: 不能添加两个指针。两个指针相加一定是野指针,就没有意义了
p = p - arr;//ok 减法可以减指针
//p = p * arr;//err
//指针乘除偏移量是不允许的,取余也不行
//p = p * 6;//err
//p = p / 6;//err
if (p > arr) {
printf("真\n");
}
if (p && arr) {
printf("指针p有值\n");
}
//三目运算符
printf("%s\n", p > arr?"p大于arr":"p小于arr");
return 0;
}
每一个元素都是一个指针,指针数组是一个二维数组模型。
#include
int main() {
int a = 87, b = 65, c= 89;
//定义数组 数据类型 数据名[元素个数]={值1,值2,值3 }
int* arr[3] = {&a,&b,&c};
//printf("%d\n",*arr[0]);//87
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
{
printf("%d\n", *arr[i]);
}
printf("指针数组大小:%d\n", sizeof(arr));//12
printf("指针元素大小:%d\n", sizeof(arr[0]));//4
return 0;
}
问1: 为什么我把int* arr[3] = {&a,&b,&c};
换成char* arr[3] = {&a,&b,&c};
得到的结果是一样的?
87
65
89
指针数组大小:12
指针元素大小:4
答: *是取值, &是取地址,因为两个不同的数组保存的是同一个地址值,所以一样。
指针数组是一个特殊的二维数组模型
#include
int main() {
//指针数组里面的元素存储的是指针
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
int* arr[] = { a,b,c };
//printf("%p\n",a);//004FFC40
//printf("%p\n",arr[0]);//004FFC40
//printf("%p\n",&a[0]);//004FFC40
//注意
//printf("%p\n", arr);//004FFC04 跟a不相等
//printf("%p\n", &arr[0]);//004FFC04
/* arr是指针数组的首地址 */
//for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
//{
// printf("%d\n",*arr[i]);//1 4 7
//}
//指针数组是一个特殊的二维数组模型
//printf("%d\n", a[1]);//2
//printf("%d\n", arr[0][1]);//2
for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
{
for (int j = 0; j < 3; j++)
{
//二维数组
//printf("%d\t",arr[i][j]);
//printf("%d\t", *(arr[i] + j));//arr[i]地址+偏移量j
// *(arr+i)=arr[i]
printf("%d\t", *(*(arr + i) + j));
}
puts("");
}
return 0;
}
指针数组对应于二级指针,最好还是用二维数组吧,比较好看。
puts(char* s)
输出更简洁、更方便。而且使用 puts() 函数连换行符 ‘\n’ 都省了,使用 puts() 显示字符串时,系统会自动在其后添加一个换行符
。s
可以是字符指针变量名
、字符数组名
,或者直接是一个字符串常量
。功能是将字符串输出到屏幕
。输出时只有遇到 ‘\0’ 也就是字符串结束标志符才会停止。puts(“”);相当于printf(“\n”);
C语言允许有多级指针存在,在实际的程序中一级指针最常用,其次是二级指针。二级指针就是指向一个一级指针变量地址的指针。
#include
int main() {
int a[] = { 1,2,3 };
int b[] = { 4,5,6 };
int c[] = { 7,8,9 };
int* arr[] = { a,b,c };
//指针数组和二级指针建立关系
int** p = arr;
printf("%d\n", **p);//1
//二级指针加偏移量 相当于跳过了一个一维数组大小
printf("%d\n", **(p + 1));//4 = arr[1][0]
//一级指针加偏移量相当于跳过一个元素
printf("%d\n", *(*p + 1));//2 = arr[0][1]
printf("%d\n", *(*(p + 1) + 1));
return 0;
}
#include
int main() {
int a = 10;
int b = 20;
int* p = &a;
int** pp = &p;
int*** ppp = &pp;
//*ppp == pp == &p
//**ppp == *pp == p == &a
//***ppp == **pp == *p == a
//*pp = &b;//等价于p=&b
//printf("%d\n",*p);//20
**pp = 666;
printf("%d",a);//666
return 0;
}
值传递:形参不影响实参的值。
#include
void replace(int a, int b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int a = 10;
int b = 20;
//值传递
replace(a, b);
printf("%d,%d", a, b);//10,20
return 0;
}
地址传递:形参可以改变实参的值。
#include
void replace(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int a = 10;
int b = 20;
//地址传递
replace(&a, &b);
printf("%d,%d", a, b);//20,10
return 0;
}
数组名做函数参数,函数的形参会退化成指针丢失精度
,因为一级指针二级指针没办法统一,所以是丢失精度。需要传递 元素个数(或叫精度)。
#include
//追加字符串
void AddStr(char* target,char* s) {
int i = 0;
for (;target[i]!=0;i++) {}
//printf("%d\n", i);//5
//printf("%d\n", strlen(target));//5,相当于strlen(target)
int j = 0;
while (s[j] != 0) {
target[i + j] = s[j];
j++;
}
//target[i + j] = '\0';//默认是0
}
int main() {
char target[100] = "hello";
char s[] = "world";
AddStr(target,s);
printf("%s\n", target);//helloworld
return 0;
}
void AddStr(char* target,char* s) {
int i = 0;
for (;*(target+i)!=0;i++) {}
//printf("%d\n", i);//5
//printf("%d\n", strlen(target));//5,相当于strlen(target)
int j = 0;
while (*(s+j)!= 0) {
*(target+i + j) = *(s+j);
j++;
}
//target[i + j] = '\0';//默认是0
}
void AddStr(char* target,char* s) {
while (*target)target++;
while (*s) {
*target = *s;
s++;
target++;
}
}
再优化一下
void AddStr(char* target,char* s) {
while (*target)target++;
while (*target++ = *s++);
}
#include
//字符串去空格
void RemoveSpace(char* s)
{
char newStr[100] = { 0 };
char* temp = newStr;
int i = 0;
int j = 0;
while (s[i] != '\0')
{
if (s[i] != ' ') {
newStr[j] = s[i];
j++;
}
i++;
}
printf("newStr:%s\n",newStr);//helloxy
while (*s++ = *temp++);
}
int main() {
char s[] = " h e l lo x y ";
RemoveSpace(s);
printf("s:%s\n", s);//helloxy
return 0;
}
其实还能优化,思路是找到不是空格就覆盖前面的值。
#include
//字符串去空格
void RemoveSpace(char* s)
{
//用来遍历字符串
char* ftemp = s;
//记录非空格字符串的
char* rtemp = s;
while (*ftemp)
{
if (*ftemp != ' ') {
*rtemp = *ftemp;
rtemp++;
}
ftemp++;
}
*rtemp = 0;
}
int main() {
char s[] = " h e l lo x y ";
RemoveSpace(s);
printf("s:%s\n", s);//helloxy
return 0;
}
#include
char* StrChr(char* s, char ch) {
int i = 0;
while (s[i])
{
if (s[i] == ch) {
return &s[i];
}
i++;
}
return NULL;
}
int main() {
char s[] = "hello xy";
char* p = StrChr(s,'x');
if (p==NULL) {
printf("未找到\n");
}
else {
printf("%s\n",p);
}
return 0;
}
结果:xy
#include
char* QueryStr(char* src,char* dest) {
//临时指针
char* fsrc=src;//给源字符串src遍历用的
char* rsrc=src;//记录相同字符串首地址
char* tdest = dest;
while (*fsrc) {
rsrc = fsrc;
while (*fsrc == *tdest && *fsrc!='\0') {//如果两字符串都是末尾"llo\0" "llo\0"会数组下标越界
fsrc++;
tdest++;
}
if (*tdest == '\0') {
return rsrc;
}
//如果不相同,我们要回滚
tdest = dest;//目标字符串更新到起始位置
fsrc = rsrc;
fsrc++;
}
return NULL;
}
int main() {
char src[] = "hello xy";
char dest[] = "llo";
char* p = QueryStr(src,dest);
printf("%s\n",p);
return 0;
}
#include
int main() {
char s[] = "hello xy";
char* p = "hello xy";
s[2] = 'm';
//p[2] = 'm';//err:写入访问权限冲突。
//*(p+2) = 'm';//err:写入访问权限冲突。
printf("%s\n", s);//hemlo xy
printf("%s\n", p);//hello xy
return 0;
}
为什么会报错?原因是因为创建字符串存储的位置是不同的。
char s[] = “hello xy”;存储的是栈区字符串
。
char* p = “hello xy”;是数据区
下的常量区字符串
,指针指向的是字符串常量区的地址。例如printf(“hello xy”);这个字符串没有一个名字去标志字符串所在的位置,所以这个字符串所在的位置就是数据区下的常量区字符串。这个字符串常量区的内容是不允许修改的。
#include
int main() {
char* p1 = "hello xy";
char* p2 = "hello xy";
printf("%p\n", p1);
printf("%p\n", p2);
return 0;
}
结果:地址一样:00A78B40。因为这两个字符串是完全一致并且不能修改,在内存中做一份就可以了,p1和p2同时指向字符串常量区的地址,并不是p1和p2不能修改,而是"hello xy"对应的区域中的数据不能修改,他们地址相同而且都不允许修改,他们是只读的,多个指针指向同一地址是可以的。
#include
int main() {
//指针数组:每个单元存储一个指针,合起来就是一个指针数组
//第一种方式
char s1[] = "favorite";
char s2[] = "person is";
char s3[] = "xy";
char* arr1[] = { s1,s2,s3 };
//字符串数组
//第二种
char* arr2[] = { "favorite","person is","xy" };
//打印
for (int i = 0; i < 3; i++)
{
printf("%s ", arr1[i]);
}
puts("");
for (int i = 0; i < 3; i++)
{
printf("%s ", arr2[i]);
}
return 0;
}
区别:arr1里面的字符串可以修改,arr2的字符串(是常量字符串,把地址放到了arr2里)不能修改。
#include
int getstr_length(char* ch ) {
//计算字符串有效长度
int i = 0;
while (ch[i]!='\0')
{
i++;
}
return i;
}
int getstr_length2(char* ch) {
//计算字符串有效长度
char* temp = ch;
while (*temp != '\0')temp++;
return temp-ch;
}
int main() {
char* ch = "hello xy";
//int length = getstr_length(ch);//8
int length = getstr_length2(ch);//8
printf("长度: %d\n",length);
return 0;
}
getstr_length 和 getstr_length2两个都行,如果不希望改变参数里面的内容可以写成getstr_length2(const char* ch)
我们平常主函数都是 main(void) 或者干脆什么都不写 main(),但是 正常情况下主函数是有两个参数的。我们程序在运行起来是通过主函数开始执行,可以对主函数进行传参的操作,我们cmd运行程序后面有时候会带一些参数,我们可以自己去捕获一下。
假设命令是 gcc -o main main.c
==> 4个参数
intargc
表示传递参数的个数
char*argv
[] = { “gcc” , “-o” ,“main” ,“main.c” } 表示参数具体内容
#include
int main(int argc,char* argv[]) {
printf("%d\n",argc);
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
这个代码我们需要单独去外边(cmd)运行一下
gcc -o main.exe main.c -std=c99
D:\cCode\VSstudyCYuYan\day08\main.exe 空格之后随便输字符串
-std=c99 c99库,因为我在循环内部定义参数应该使用c99编辑器,
for (int i = 0;
可以看到输出了D:\cCode\VSstudyCYuYan\day08\main.exe
,这个是我们的运行程序,运行程序也算作参数的一个,它自己能把自己捕获到,算作字符串中的第一个。我输入的命令是6个字符串。
我们还可以加个判断,如果缺少参数我们就不给他运行下去
#include
int main(int argc,char* argv[]) {
//printf("%d\n",argc);
if (argc < 3) {
printf("需要2个参数\n");
return -2;
}
for (int i = 0; i < argc; i++)
{
printf("%s\n", argv[i]);
}
return 0;
}
argv[]不是在其他程序调用传递的,而是在执行应用程序的时候传递的。很多程序会有这个内容,但是用不到它,写起来也麻烦,有时候我们就不写。如果你想传递参数的情况下,用这两个参数去传递去接收。比如你要想编译程序的情况下,你就知道哪个是源程序哪个是其他程序。