动态内存分布malloc
1.需用头文件#include<stdlib.h>
void* malloc(size_t size);
返回结果是void*。
(int*)malloc(n*sizeof(int))
2.malloc申请的空间大小是以字节为单位的
eg.用malloc动态分布倒序输出n个数
#include<stdio.h>
#include<stdlib.h>
int main(){
int num;
int* a;
int i;
scanf("%d",&num);
a=(int*)malloc(num*sizeof(int));
if (a == NULL) { // 检查malloc是否成功分配内存
printf("Memory allocation failed!\n");
return 1; // 分配失败时返回1
}
for(i=0;i<num;i++){
scanf("%d",&a[i]);
}
for(i=num-1;i>=0;i--){
printf("%d ",a[i]);
}
free(a);//解放内存
}
字符串
字符串的表达
1.数组:为的是构建(结尾输出要有“\0")
2.指针:1>作为函数参数。2>动态内存分布。
字符串的输入与输出
char string[8];
scanf("%s",string);
printf("%s",string);
此处scanf读入一个单词(到空格,tab,回车为止)。
但是要注意,这个输入不完全,因为不知道读入的长度。
应在%与s中间加入一个数表示最多读入。
char* string;
scanf("%d",string);
此处char*是一个指针,指到某个位置。而没对string初始化,所以可能导致char*指向某个错误位置导致程序崩溃。
正序输出数字的拼音
还记得第一周我们学习switch-case时有一道这样的题目,当时我们用了很麻烦的方法
#include<stdio.h>
int main(){
int n;
scanf("%d", &n);
if (n < 0) {
printf("fu ");
n = -n; // 转换为正数处理
}
do {
int d = n % 10; // 直接取当前最低位
switch (d) {
case 0: printf("ling"); break;
case 1: printf("yi"); break;
case 2: printf("er"); break;
case 3: printf("san"); break;
case 4: printf("si"); break;
case 5: printf("wu"); break;
case 6: printf("liu"); break;
case 7: printf("qi"); break;
case 8: printf("ba"); break;
case 9: printf("jiu"); break;
}
if (n > 9) // 如果n大于9,说明还有更高位需要打印,打印空格
printf(" ");
n /= 10; // 缩小n,准备处理下一位
} while (n > 0); // 当n为0时,说明所有位都已处理完毕
return 0;
}
其中出现了代码重复,而在我们学习了数组和字符串之后我们可以修改以上代码。
#include<stdio.h>
#include<string.h>
const char* pinyin[]={"ling","yi","er","san","si","wu","liu","qi","ba","jiu"};
void printpinyin(int num){
if(num<0){
num=-num;
printf("fu ");
}
if(num==0){
printf("ling");
return;
}
int a[100];
int cnt=0;
while(num>0){
a[cnt++]=num%10;
num/=10;
}
for(int i=cnt-1;i>=0;i--){
printf("%s",pinyin[a[i]]);
if(i>0){
printf(" ");
}
}
printf("\n");
}
int main(){
int num;
scanf("%d",&num);
printpinyin(num);
return 0;
}
putchar&getchar
int putchar(int c)
类型为int,但向标准输出只写入一个字符,返回一次写了几个字符。若输出出现问题返回EOF(-1)
int getchar(void)
返回从标准输入读到的一个字符,返回也为int。为了返回EOP(?没搞太懂)
区别于scanf,scanf一次读入%d后一个整体,而getchar是一个字节一个读入。
为便于理解可以试运行以下代码:
#include<cstdio>
int main()
{
int ch;
while((ch=getchar())!=EOF){
putchar(ch);
}
printf("EOF\n");
return 0;
}
strlen记字符串长度
size_t strlen (const char*s);
返回s的字符串长度(不包括0)。
用strlen输出hello的一字符串长度,与字节长度(做比较)
#include<stdio.h>
#include<string.h>
int len(const char* s){
int c=0;
int i=0;
while(s[i]){
i++;
c++;
}
return c;
}
int main(){
char l[]="hello";
printf("strlen=%lu\n",len(l));
printf("sizeof=%lu\n",sizeof(l));
}
strcmp做字符串大小比较
strcmp 函数比较两个字符串并返回以下值:
负值:如果第一个字符串小于第二个字符串
零:如果两个字符串相等
正值:如果第一个字符串大于第二个字符串
eg.
#include<stdio.h>
#include<string.h>
int main(){
char s1[]="abc";
char s2[]="abc";
printf("%d\n",strcmp(s1,s2));
}
strcmp(s1, s2) 比较 s1 和 s2。因为 C 语言的字符比较是基于 ASCII 值的,具体的比较过程如下:
s1[0] 是 'a',ASCII 值是 97
s2[0] 是 'A',ASCII 值是 65
在比较第一个字符时,'a' 的 ASCII 值(97)大于 'A' 的 ASCII 值(65),所以 strcmp(s1, s2) 返回一个正值。在许多系统上,这个正值通常为 1(表示第一个字符串比第二个字符串大),但具体的正值取决于实现。
而部分的编译器会输出32
至于为什么不是 32,这是因为 strcmp 返回的是一个负值、零或正值,不一定是字符差值。返回值的大小(正值、负值)可能由具体的库实现决定,但返回正值表示 s1 比 s2 大是固定的。
strcpy将后一个字符串拷贝到前一个字符串
char* strcpy(char* restrict dst,const char* restrict src);
把src的字符串拷贝到dst,包括("\0")
restrict表示src和dst不重叠
返回dst
理解代码
#include<stdio.h>
#include<string.h>
char* mycpy(char* dst,const char* src){
char* ret=dst;
while(*src){
*dst++=*src++;
}
*dst='\0';
return ret;
}
int main(){
char s1[]="abc";
char s2[]="Abc";
mycpy(s1,s2);
printf("%s",s1);
}
strcat做连接
char* strcat(char* restrict s1,const char* restrict s2);
把s2拷贝到s1后面,接成一个长的字符串
返回s1
同时
注意s1必须要有足够的空间
strcpy和strcat的安全问题
问在在于目的地是否有足够的空间
此为安全版本
char* strncpy(char *restrict dst,const char *restrict src,size_t n);
char *strncat(char *restrict s1,const char *restrict s2,size_t n);
int strncmp(const char *s1,const char *s2,size_t n);//此处n是只是对前n个字符做比较
多了几个n。n是最多可输入字符。
strchr与strrchr找字符位置
char *strchr(const char*s,int c);
从左到右找c第一次出现的位置,返回指针、
char *strrchr(const char*s,int c);
从右到左。
返回null表示没找到。
输出hello中 l 后的字符串
#include<stdio.h>
#include<string.h>
int main(){
char s[]="hello";
char *p=strchr(s,'l');
printf("%s\n",p);
}
而输出 l 后第二个字符
#include<stdio.h>
#include<string.h>
int main(){
char s[]="hello";
char *p=strchr(s,'l');
p=strchr(p+1,'l');
printf("%s\n",p);
}
在p指向的位置往后移一位。
那如何输出 l 前的字符呢
输出l前的字符
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(){
char s[]="hello";
char *p=strchr(s,'l');
char c=*p;
*p='\0';
char *t=(char*)malloc(strlen(s)+1);
strcpy(t,s);
printf("%s\n",t);
free(t);
}
此处是将 l 处由 l 变为\0再输出s
//最后可以将*p=c,把l还回去。
字符串中找字符串
char *strstr(const char *s1,const char *s2);
寻找字符串
char *strcasestr(const char *s1,const char *s2);
寻找字符串,并忽视大小写。
枚举
枚举是一种用户定义的数据类型,它用enum以如下语法来声明:
enum 枚举类型名字 {名字0,。。。,名字n};
枚举类型名字通常并不真的使用,要用的是在大括号的里面的名字,因为它们就是常量符号,他们的类型是常量符号,他们的类型是int,值则依次从0到n,如
enum color{red,yellow,green};
eg喜欢的颜色
#include<cstdio>
const int red=0;
const int yellow=1;
const int green=2;
int main(){
int color=-1;
char *colorname=NULL;
printf("输入喜欢的颜色代码:");
scanf("%d",&color);
switch(color){
case red:colorname="red";break;
case yellow:colorname="yellow";break;
case green:colorname="green";break;
default:colorname="unkown";break;
}
printf("喜欢的颜色是%s\n",colorname);
return 0;
}
此代码为不用枚举的方法,很明显定义处有点冗杂。那么如果用enum来替代const int如何呢:
#include<cstdio>
enum color{red,yellow,green};
int main(){
int color=-1;
char *colorname=NULL;
printf("输入喜欢的颜色代码:");
scanf("%d",&color);
switch(color){
case red:colorname="red";break;
case yellow:colorname="yellow";break;
case green:colorname="green";break;
default:colorname="unkown";break;
}
printf("喜欢的颜色是%s\n",colorname);
return 0;
}
在enum中可以在最后定义一个字符表示enum定义了几个数
#include<cstdio>
enum color{red,yellow,green,numcolors};
int main(){
int color=-1;
char *colornames[numcolors]={"red","yellow","green"};
char *colorname=NULL;
printf("输入喜欢的颜色代码:");
scanf("%d",&color);
if(color>=0&&color<numcolors){
colorname=colornames[color];
}else{
colorname="unkown";
}
printf("喜欢的颜色是%s\n",colorname);
return 0;
}
这样要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便了
枚举量
声明枚举量的的时候可以指定值
#include<cstdio>
enum color{red=1,yellow,green=5,numcolors};
int main(){
printf("%d",green);
}
而yellow跟在red=1后所以yellow是2