1.什么是字符串?
相当于字符数组,和整型数组一个道理
char str[] = {'h','e','l','l','o'}; 等价于 char *p = ''hello'';
区别在于第一个是字符串变量,第二个是字符串常量(不允许随意修改)
#include <stdio.h>
int main()
{
int data[] = {1,2,3,4,5};
char cdata[] = {'h','e','l','l','o'};
char cdata2[] = "hello";
char *pchar = "hello";//字符串常量,不允许被修改
char c = 'c';
printf("%s",pchar);
putchar('\n');
puts(pchar);
/*
int i;
for(i=0;i<5;i++)
{
printf("%c",*(pchar+i));
}*/
return 0;
}
和整型数组的区别:多了结束标志'\0'.
2.sizeof 和strlen的区别
sizeof是计算数据类型或变量所占的内存大小,sizeof是计算字符串中的'\0',如果指针的内存用sizeof来计算的时候,得出的是计算机用多少字节来表示一个地址。
strlen是一个函数,主要计算字符串的实际长度。
3.动态开辟字符
malloc函数,分配所需的内存空间,并返回一个指向它的指针
realloc函数,扩容,重新调整之前用malloc所分配的ptr指向内存块的大小
free函数,释放之前调用的malloc和realloc,calloc函数所分配的内存空间。既防止内存泄漏,也防止悬挂指针(野指针的一种)
4.几种字符串常用的函数
输出字符串 puts()
获取字符串scanf()/ gets()
计算字符串的长度strlen
拷贝的三种表现形式
#include <stdio.h>
char *myStrcpy(char *des,char *src)
{
if(des == NULL || src == NULL)
{
return NULL;
}
char *bak = des;//备份目标地址
while(*src != '\0')
{
*des = *src;
des++;
src++;
}
*des = '\0';
return bak;
}
char *myStrcpy2(char *des,char *src,int count)
{
if(des == NULL || src == NULL)
{
return NULL;
}
char *bak = des;//备份目标地址
while(*src != '\0'&& count>0)
{
*des++ = *src++;
count--;
}
*des = '\0';
return bak;
}
char *myStrcpy3(char *des,char *src)
{
if(des == NULL || src == NULL)
{
return NULL;
}
char *bak = des;//备份目标地址
while((*des++ = *src++)!= '\0');
*des = '\0';
return bak;
}
int main()
{
char str[128] = {'\0'};
char *p = "xiaoming handsome";
myStrcpy2(str,p,6);
puts(str);
return 0;
}
拼接 strcat函数,在一个字符串的后面追加一个字符串。strcat(str1,str2),将str2追加到str1的后面。以下是通过指针和函数展现的字符串拼接的代码。首先指针des指向的是目标字符串的'\0'的位置,指针src指向的是目标字符串的首地址,随着des指针和src指针同时向后移动src所指向的数值就被添加到des的后面,进而完成拼接。
#include <stdio.h>
#include <string.h>
#include <assert.h>
char* myStrcat(char *des,char *src)
{
assert(des!='\0'&&src!='\0');
char *bak = des;
while(*des != '\0')
{
des++;
}
while((*des++=*src++)!='\0');
*des = '\0';
return bak;
}
int main()
{
char str[128] = "xiaoming";
char *p2;
char *p = "handsome";
p2 = myStrcat(str,p);
puts(str);
puts(p2);
return 0;
}
strcmp函数比较两个字符串的大小,strcmp(str1,str2)如果是str1=str2,则返回零;如果str1<str2,则返回负数,如果str1>str2,则返回正数。
#include <stdio.h>
#include <string.h>
#include <assert.h>
int myStrcmp(char *str1,char *str2)
{
int ret = 0;
while(*str1 && *str2 &&(*str1==*str2))
{
str1++;
str2++;
}
ret = *str1 - *str2;
if(ret<0)
{
ret = -1;
}
if(ret>0)
{
ret = 1;
}
return ret;
}
int main()
{
char *p1 = "xiaomingd";
char *p2 = "xiaomingb";
int ret = myStrcmp(p1,p2);
if(ret==0)
{
puts("两个字符串一样");
}
printf("RET = %d\n",ret);
return 0;
}
结构体
1.为什么要用结构体
我们需要用很多类型的数据来表示一个整体,不同数据类型的集合就要用到结构体。
2.定义一个结构体
struct Student
{
int num;
char name[32];
char sex;
int age;
double score;
char addr[32];
};
用struct时后面根据编程习惯,必须大写字母开头,最后大括号外面的结尾不能落下。
每一个成员都是结构体中的一个域,也称为域表。
3.初始一个结构体变量并引用
#include <stdio.h>
#include <string.h>
struct Student
{
int num;
char name[32];
char sex;
int age;
double score;
char addr[32];
};
int main()
{
int arr[] = {1,2,3};
int i;
int len;
struct Student arr2[3] = {{2,"小明",'g',17,99.5,"北京"},
{3,"小红",'M',18,89.2,"山东"},
{4,"小王",'f',19,100,"新疆"}
};
len = sizeof(arr)/sizeof(arr[0]);
for(i=0;i<len;i++)
{
printf("学号:%d,年龄:%d,分数:%lf,名字:%s,地址:%s\n",arr2[i].num
,arr2[i].age,arr2[i].score,arr2[i].name,arr2[i].addr);
}
return 0;
}
共用体/联合体
1.结构体元素有各自单独空间,共用体元素共享空间,空间大小由最大类型确定。
2.结构体元素互不影响,共用体赋值会导致覆盖
#include <stdio.h>
struct TestT
{
int idata;
char cdata;
int ddata;
};
union TestU
{
int idata;
char cdata;
int ddata;
};
int main()
{
struct TestT t1;
union TestU u1;
printf("结构体t1的大小是:%d\n",sizeof(t1));
printf("联合体u1的大小是:%d\n",sizeof(u1));//占用空间取决于最大的类型所占用的空间
t1.idata = 10;
t1.cdata = 'a';
t1.ddata = 20;
printf("idata:%p,%d\n",&t1.idata,t1.idata);
printf("cdata:%p,%d\n",&t1.cdata,t1.cdata);
printf("ddata:%p,%d\n",&t1.ddata,t1.ddata);
u1.idata = 10;
u1.ddata = 20;
printf("idata = %d\n",u1.idata);
printf("cdata:%p,%d\n",&u1.idata);
printf("idata:%p,%d\n",&u1.cdata);
printf("idata:%p,%d\n",&u1.ddata);
return 0;
}
同时也要注意数据覆盖