字符串:
字符串变量是字符串的首地址,直到'\0'为止
字符串的表示方式:1 字面值”abc”(字符串常量)
2 char *表示
3 char s[n]表示
字符串的操作 :
1 字符串的赋值
= 改的是地址 和 strcpy()改的是值
char *s1=”abc” 通过 = 赋值操作
这一句可分解为三部分:
a 声明;
b 在只读常量区申请地址存放“abc”;
c 赋值
char s2[4]=”abc”;
a 数组可以看作是常指针,不能改指向;
b 表示把“abc” 只读常量区内
容赋值到数组等号 = 右边“abc”在只读常量区
strcpy(s1,"123"); 通过 strcpy() 赋值操作
**********************************************
char* s1 = "abc";
char s2[4] = "abc";
s1 = "123";
//strcpy(s1,"123"); //error 只读区的内容不可以更改
//s2 = "123"; //error
常指针不能改地址,数组名简单看作常指针不可改变地址,不能做自加自减操作
char* s3 = malloc(4);
//s3 = "abc"; //error s3
指向了只读区,堆区内存丢了 ,导致内存泄露
**********************************************
2 字符串的比较
== 比地址 和 strcmp() 比值
在只读常量区中 公用相同值的字符串 字符串值相同的只有一份 相同值的字符串地址也相同
char* s4 = "123"; char* s5 = "123"; //s4 和 s5都在只读存储区
char s6[4] = "123"; char s7[4] = "123"; // s6 和 s7都是在栈区
printf("%d\n",s4 == s5); //1 比较的是地址 只读存储区中,相同值得字符串地址也相同
printf("%d\n",strcmp(s4,s5)==0); //1 比较的是值
printf("%d\n",s7 == s6); //0 比较的是地址
printf("%d\n",strcmp(s6,s7)==0);
//1
比较的是值
3 字符串的拼接 比如拼接文件路径和文件名
char* name = "dsanmux";
char* path = "/home/user";
char buf[50] = { }; //使用过程中先进行初始化
sprintf(buf,"%s/%s",path,name); //sprintf 用于字符串拼接 (字符串拼接方法之一)
//strcpy(buf,path); //strcpy和strcat连用完成字符串拼接(字符串拼接方法二)
//strcat(buf,"/");
//strcat(buf,name);
printf("buf=%s\n",buf);
4 用指针操作字符串 比如拆分字符串
方法一
char* message = "dsanmux,25";
char mname[20] = { };
char age[10] = { };
int i;
for(i=0;*(message+i)!=',';i++);
strncpy(mname,message,i);
strcpy(age,message+i+1);
方法二
int flag = 1; //1代表,之前 遇到,改为0 ;定义一个变量进行状态判断通过给定flag = 1和flag = 0的变化来确定某一个状态的变化,程序中常用
int i=0,pos;
while(*message)
{
if(flag)
{
if(*message==',')
{
flag = 0;
pos = i;
i++;
message++;
continue;
}
mname[i] = *message;
}
else
{
age[i-pos-1] = *message;
}
i++;
message++;
}
printf("mname=%s:age=%s\n",mname,age);
5 字符串的长度和容量
长度:strlen()是数据有多少 ;
容量:是sizeof()是 最大能放多少个 ;
char buf1[100] = { };
strcpy(buf1,"123");
printf("length=%d,size=%d\n",strlen(buf1), sizeof(buf1));
6 字符串和int/double之间转换:
//sprintf() sscanf()
int a1;
char buf2[10] = "123";
sscanf(buf2,"%d",&a1);//字符串->int
printf("a1=%d\n",a1);
char buf3[10] = { };
sprintf(buf3,"%d",a1);
printf("buf3=%s\n",buf3);
指针:
指针是地址
指针变量是变量,是用于存放地址(指针)的变量
内存:
1.函数形参位于栈区,函数gettingspace(str);执行完毕形参将自动释放,从而导致指向(char*)malloc(100);指针释放导致内存泄漏
void gettingspace(char *p_addr)
{
p_addr = (char*)malloc(100);
}
void test(void)
{
char *str = NULL;
gettingspace(str);
strcpy(str,"dsanmux");
printf("%s\n",str);
}
char* gettingspace(void)
{
char* p_addr = (char*)malloc(100);
return
p_addr
}
void test(void)
{
char *str = NULL;
str = gettingspace();
strcpy(str,"dsanmux");
printf("%s\n",str);
}
返回指向堆内存的指针是可以的程序在运行的时候用 malloc 申请任意多少的内存,程序员自己负责在何时用 free释放内存。动态内存的生存期由程序员自己决定,使用非常灵活。
2.返回值返回局部变量地址,gettingspace()执行完毕,栈内存释放,str指向不存在的内存,
如果函数的返回值非要是一个局部变量的地址,那么该局部变量一定要申明为static类型
void *gettingspace(void)
{
char p_addr[] = "dsanmux"; // static char p_addr[] = "dsanmux";
return p_addr;
}
void test(void)
{
char *str = NULL;
str = gettingspace();
printf("%s\n",str);
}
3 .函数形参位于栈区,函数gettingspace(str,100);执行完毕形参将自动释放,从而导致指向(char*)malloc(100);指针释放导致内存泄漏
void gettingspace(char **p_addr,int num)
{
*p_addr = (char*)malloc(100);
}
void test(void)
{
char *str = NULL;
gettingspace(&str,100);
strcpy(str,"dsanmux");
printf("%s\n",str);
}
4.
void test(void)
{
char *str =
(char*)malloc(100);
gettingspace(str);
strcpy(str,"dsanmux");
printf("%s\n",str);
}
5.char *gettingspace()
{
char *p="dsanmux";
return p;
}
int main()
{
char *str;
str=returnStr();
printf("%s\n", str);
return 0;
}
因为"dsanmux"是一个字符串常量,存放在只读数据段,把该字符串常量存放的只读数据段的首地址赋值给了指针,所以returnStr函数退出时,该该字符串常量所在内存不会被回收,故能够通过指针顺利无误的访问。
6.数组是不能作为函数的返回值的,原因是编译器把数组名认为是局部变量(数组)的地址。返回一个数组一般用返回指向这个数组的指针代替,而且这个指针不能指向一个自动数组,因为函数结束后自动数组被抛弃,但可以返回一个指向静态局部数组的指针,因为静态存储期是从对象定义到程序结束的。
int* gettingspace( void )
{
static int a[10];
........
return a;
}
函数是可以返回局部变量的。 局部变量的作用域只在函数内部,在函数返回后,局部变量的内存已经释放了。因此,如果函数返回的是局部变量的值,不涉及地址,程序不会出错。
但是如果返回的是局部变量的地址(指针)的话,程序运行后会出错。
因为函数只是把指针复制后返回了,但是指针指向的内容已经被释放了,这样指针指向的内容就是不可预料的内容,调用就会出错。
准确的来说,函数不能通过返回指向栈内存的指针(注意这里指的是栈,返回指向堆内存的指针是可以的)。