赞
踩
&
是取地址符号 是升
纬度的
*
是取值符号 是降维
度的
指针就是内存中的一个地址编号,指针变量用于存储地址,指针变量也是一个变量。
#include<stdio.h>
int main(void) {
int a = 0xaabbccdd;
printf("%p\n", &a);//获取a的内存地址
return 0;
}
内存中的每一个数据都会分配相应的地址
char 占内存一
个字节
,分配一
个地址
int 占内存四
个字节
,分配四
个地址
windows电脑在做数据存储时采用小端对齐(低位数据
放在低位内存地址
,高位数据
放在高位内存地址
)。
大端对齐:低位数据放在高位内存地址,高位数据放在低位内存地址。
计算机的字节顺序模式分为大端数据模式和小端数据模式,它们是根据数据在内存中的存储方式来区分的。小端对齐和大端对齐都是计算机中数据存储的一种方式。
数据类型* 变量名
定义指针类型变量
*变量名 = 值通过指针间接修改变量的值
#include<stdio.h>
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<stdio.h>
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 <stdio.h>
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 <stdio.h> 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 <stdio.h>
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 <stdio.h>
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 <stdio.h>
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 <stdio.h> 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 <stdio.h> 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 <stdio.h> 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 <stdio.h> //数组作为函数参数会退化为指针,丢失了数组的精度 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 <stdio.h> /* 冒泡排序 */ //数组作为函数参数会退化为指针,丢失了数组的精度 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 <stdio.h>
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<stdio.h> //字符串拷贝的操作 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<stdio.h> 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<stdio.h> 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 <stdio.h> 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 <stdio.h> 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<stdio.h> 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<stdio.h> 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<stdio.h> 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<stdio.h> 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<stdio.h> //追加字符串 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<stdio.h> //字符串去空格 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<stdio.h> //字符串去空格 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<stdio.h> 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 <stdio.h> 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 <stdio.h>
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 <stdio.h>
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 <stdio.h> 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 <stdio.h> 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 <stdio.h>
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 <stdio.h> 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[]不是在其他程序调用传递的,而是在执行应用程序的时候传递的。很多程序会有这个内容,但是用不到它,写起来也麻烦,有时候我们就不写。如果你想传递参数的情况下,用这两个参数去传递去接收。比如你要想编译程序的情况下,你就知道哪个是源程序哪个是其他程序。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。