这是关于 C 语言字符串操作 和 二分查找基础概念 的笔记,以下是核心知识点总结:
int mid = (begin + end) / 2
int main(void) //利用二分法查找数。使用二分法需要对数组先进行排序。
{
int a[]={1,2,3,4,5,6,7,8,9,10};
int len=sizeof(a)/sizeof(a[0]);
int begin=0,end=len-1;
int n;
scanf("%d",&n);
int middle;
while(begin<=end)
{
middle=(begin+end)/2;
if(a[middle]>n)
{
end=middle-1;
}
else if(a[middle]
这段代码实现了二分法查找算法,其核心思想可以概括为以下几点:
前提条件:二分法查找的前提是数组必须已经排好序(这里是升序排列的数组a
)
核心思路:通过不断将查找范围减半来快速定位目标值
begin
(初始为0)和结束点end
(初始为数组最后一个元素的索引)middle
,将目标值n
与中间位置的元素a[middle]
比较a[middle]
大于n
,说明目标值在左半部分,调整end
为middle-1
a[middle]
小于n
,说明目标值在右半部分,调整begin
为middle+1
终止条件:
break
跳出循环begin
大于end
时,说明整个数组已查找完毕但未找到目标值时间复杂度优势:二分法查找的时间复杂度为O(log₂n),相比顺序查找的O(n),在数据量较大时效率显著提高
这种方法的关键在于每次比较后都能排除一半的查找范围,从而快速逼近目标值或确定目标值不存在。
字符串结束标志:'\0'
(ASCII 值为 0,是 C 语言识别字符串结束的标记)
char st[100] = {'a', 'b', 'c'};
'\0'
,但需注意手动初始化时要预留 '\0'
位置。char s[100] = "Hello";
'\0'
,实际占用 6 个字符(H e l l o \0
)。字符串长度与存储:
sizeof(s)
:计算数组总大小(如 char s[100]
结果为 100,包含未使用空间)。strlen(s)
:计算有效字符长度(从首地址到 '\0'
的字符数,不包含 '\0'
)。gets(s)
:scanf("%s", s)
:fgets(s, sizeof(s), stdin)
:sizeof(s)
限制读取长度(防止越界),会保留换行符(需手动处理时可 s[strcspn(s, "\n")] = '\0';
清除)。int main(void)
{
int i=0;
char s[10]="Hello";
// scanf("%s",&s);
// fgets(s,sizeof(s),stdin);
while(s[i]!='\0')
{
if(s[i]>='a'&&s[i]<='z')
{
s[i]-=32;
}
++i;
}
puts(s);
return 0;
}
这段代码的功能是将字符串中的所有小写字母转换为大写字母并输出。
代码的核心逻辑如下:
s
并初始化为"Hello"while
循环遍历字符串,直到遇到字符串结束符'\0'
a-z
之间)puts
函数输出转换后的字符串由于初始字符串是"Hello",其中只有字母’l’是小写,所以程序会将其转换为大写,最终输出"HELLO"。
代码中还注释了两种输入方式:
scanf("%s",&s);
:可以从标准输入读取字符串fgets(s,sizeof(s),stdin);
:也可以从标准输入读取字符串,相对更安全如果启用其中一种输入方式,程序就可以处理用户输入的任意字符串,将其中的小写字母全部转换为大写字母后输出。
函数 | 特点 | 适用场景 | 缺点 |
---|---|---|---|
gets |
读一行(含空格),到换行停止 | 旧代码兼容 | 不安全(易越界) |
scanf |
读字符串,遇空格/换行/制表符停止 | 读简单无空格内容 | 无法读带空格的字符串 |
fgets |
读一行(含空格),可限制长度 | 安全读用户输入 | 会把换行符 \n 存进去 |
fgets
处理换行符:
如果用 fgets(s, sizeof(s), stdin)
,输入 abc
后,s
里实际是 abc\n\0
,想去掉 \n
可这样:
s[strcspn(s, "\n")] = '\0'; // strcspn 找 "\n" 位置,替换成 '\0'
int main(void)
{
char s[100];
fgets(s,sizeof(s),stdin);
int i=0;
int counter1=0;
int counter2=0;
int counter3=0;
int counter4=0;
while(s[i]!='\0')
{
if(s[i]>=32&&s[i]<=47)
{
++counter1;
}
else if(s[i]>='A'&&s[i]<='Z')
{
++counter2;
}
else if(s[i]>='a'&&s[i]<='z')
{
++counter3;
}
else if(s[i]>='0'&&s[i]<='9')
{
++counter4;
}
++i;
}
printf(" %d,%d,%d,%d\n",counter1,counter2,counter3,counter4);
return 0;
}
这段代码的功能是统计用户输入字符串中不同类型字符的数量,具体来说是统计:
代码的工作流程如下:
s
用于存储输入的字符串fgets
函数从标准输入(键盘)读取字符串,最多读取99个字符(因为要留一个位置给字符串结束符’\0’)while
循环遍历字符串中的每个字符,直到遇到字符串结束符’\0’需要注意的是,ASCII码32-47范围包含了空格、!、"、#、$、%、&、'、(、)、*、+、,、-、.、/这些字符,代码将它们都归为一类统计。
例如,如果用户输入"Hello World! 123",程序会统计:
)strcpy(s2, s1)
:把字符串 s1
的内容复制到 s2
(覆盖 s2
原有内容),需保证 s2
空间足够。
strcpy
陷阱:char s1[5], s2[] = "abcdef";
strcpy(s1, s2); // 危险!s1 只有 5 空间,s2 带 '\0' 是 6 字符,会越界写内存
int main(void)
{
int i;
char s[]="hello";
char t[100]; //////!!!!!!拷贝到的空间要比被拷贝的空间大。
while(s[i]!='\0')
{
t[i]=s[i];
++i;
}
t[i]='\0';
// strcpy(t,s); //复制
puts(t);
return 0;
}
这段代码的功能是将一个字符串从一个字符数组复制到另一个字符数组,并输出复制后的字符串。
代码的核心逻辑如下:
s
并初始化为"hello"t
,预留了足够的空间(100个字符)while
循环遍历源字符串s
,直到遇到字符串结束符'\0'
s
的每个字符依次复制到目标字符串t
的对应位置t
的末尾添加字符串结束符'\0'
puts
函数输出复制后的目标字符串t
代码中特别注释了"拷贝到的空间要比被拷贝的空间大",这是字符串复制的重要原则,以避免目标数组空间不足导致的缓冲区溢出问题。
对于示例中的"hello"字符串,它包含5个有效字符加1个结束符,共6个字符,而目标数组t
有100个字符的空间,完全满足复制需求,因此程序会成功输出"hello"。
代码中还注释了strcpy(t,s);
,这是C语言标准库string.h
中提供的字符串复制函数,其功能与这段代码实现的逻辑相同,都用于将源字符串复制到目标字符串。使用strcpy
函数时同样需要保证目标数组有足够的空间,并且需要在代码开头添加#include
。
这种字符串复制方式的关键是不仅要复制有效字符,还要记得在目标字符串的末尾添加结束符'\0'
,否则可能导致字符串处理函数无法正确识别字符串的结束位置。
strcat(s2, s1)
:把字符串 s1
拼接到 s2
末尾(需保证 s2
有足够空间容纳拼接后内容)。
strcat
陷阱:'\0'
结尾),且要预留拼接后的空间:char s1[10] = "a", s2[] = "bc";
strcat(s1, s2); // 安全(s1 空间够:"a"+"bc" = "abc" + '\0',总长度 4 ≤ 10)
int main(void) //字符型数组的拼接。
{
int i=0,j=0;
char a[100]="Hello";//目标数组要确定有足够大的空间。
char b[100]="World";
while(a[i]!='\0')
{
++i;
}
while(b[j]!='\0')
{
a[i]=b[j];
++j;
++i;
}
a[i]='\0';
puts(a);
// strcat(a,b);
return 0;
}
这段代码的功能是实现两个字符串的拼接(连接)操作,将第二个字符串的内容追加到第一个字符串的末尾。
代码的核心逻辑如下:
a
和b
,分别初始化为"Hello"和"World"a
作为目标数组,需要有足够大的空间来容纳拼接后的字符串(注释中特别强调了这一点)while
循环找到a
字符串的结束位置(即'\0'
所在的索引),此时i
的值就是a
的长度while
循环将b
字符串的每个字符依次复制到a
字符串结束位置的后面
b[j]
赋值给a[i]
i
和j
,实现位置后移'\0'
作为结束标志puts
函数输出拼接后的字符串对于示例中的两个字符串,拼接后会形成"HelloWorld"并输出。
代码中还注释了strcat(a,b);
,这是C语言标准库string.h
中提供的字符串拼接函数,其功能与这段代码实现的逻辑完全一致。使用strcat
函数时需要注意:
a
必须有足够的空间容纳原字符串a
和b
的内容以及结束符#include
才能使用该函数这种字符串拼接方式的关键是先找到第一个字符串的结束位置,再从该位置开始追加第二个字符串的内容,最后别忘了添加新的结束符。
strcmp(s1, s2)
:按ASCII 码逐字符比较两个字符串:
<0
:s1
小于 s2
(前序字符 ASCII 更小)。=0
:s1
和 s2
完全相同。>0
:s1
大于 s2
(前序字符 ASCII 更大)。int main(void)
{
char a[100]="hello";
char b[100]="hel";
int i=0;
while(a[i]==b[i]&&a[i]!='\0'&&b[i]!='\0')
{
++i;
}
if(a[i]-b[i]>0)
{
printf("数组a更大");
}
else
{
printf("数组b更大");
}
return 0;
}
这段代码的功能是比较两个字符串的大小,其核心逻辑与C语言标准库中的strcmp
函数类似,用于判断两个字符串的字典顺序关系。
代码的执行过程如下:
定义了两个字符串数组a
和b
,分别初始化为"hello"和"hel"
使用while
循环逐个比较两个字符串对应位置的字符:
i
递增,继续比较下一组字符循环结束后,通过比较当前位置字符的ASCII码差值判断大小:
a[i] - b[i] > 0
,说明a
字符串更大(在字典顺序中更靠后)b
字符串更大或两者相等对于示例中的"hello"和"hel":
i=3
时,a[3]
是’l’(ASCII码108),而b[3]
是字符串结束符’\0’(ASCII码0)108 - 0 = 108 > 0
,因此会输出"数组a更大"这种比较方式遵循字典排序规则:
如果需要更精确的判断(区分相等的情况),可以在条件判断中增加对a[i] == b[i]
的检测,此时会返回0表示两个字符串完全相等。
#include
int main(void) //在三个字符型数组里找出最大的字符型数组。
{
char s1[100]="Hello";
char s2[100]="Hello!";
char s3[100]="Hello!!";
char max[100];
if(strcmp(s1,s2)>0)
{
strcpy(max,s1);
}
else
{
strcpy(max,s2);
}
if(strcmp(max,s3)<0)
{
strcpy(max,s3);
}
puts(max);
return 0;
}
strlen
细节:只算到 '\0'
为止,不包含 '\0'
。比如 str:len("abc")
结果是 3
,而 sizeof("abc")
是 4
(含 '\0'
)。
int main(void) //判断有效字符的个数,即除了'\0'外都为有效字符。
{
int i=0;
char s[10]="Hello";
while(s[i]!='\0')
{
++i;
}
printf("%d\n",i);
// strlen(s); //查看数组的有效字符
return 0;
}
这段代码的功能是计算字符串中有效字符的个数(不包括字符串结束符'\0'
)。
代码的核心逻辑如下:
s
并初始化为"Hello"i
作为计数器,初始值为0while
循环遍历字符串,条件是当前字符不是结束符'\0'
'\0'
),计数器i
就加1i
的值就是字符串中有效字符的个数,通过printf
输出对于初始字符串"Hello",它包含5个有效字符(‘H’、‘e’、‘l’、‘l’、‘o’),所以程序会输出5
。
代码中还注释了strlen(s);
,这是C语言标准库string.h
中提供的字符串长度计算函数,其功能与这段代码实现的逻辑完全一致,都用于获取字符串中有效字符的个数(不包括'\0'
)。如果要使用strlen
函数,需要在代码开头添加#include
。
这种计算方式的关键是利用了C语言中字符串以'\0'
作为结束标志的特性,通过检测这个结束标志来确定字符串的有效长度。
这些是 C 语言字符串处理的基础,实际开发中要注意 数组越界 和 '\0'
的正确处理,避免程序崩溃或逻辑错误。
字符型数组的逆序
:int main(void)
{
char s[100]="Hello";
int len,i;
len=strlen(s); //len求的是有效字符的长度。
for(i=0;i
这段代码的功能是将字符串进行反转(逆序)处理并输出结果。
代码的核心逻辑如下:
s
并初始化为"Hello"strlen(s)
计算字符串的有效长度(不包含结束符'\0'
),并将结果存储在len
中for
循环实现字符串反转:
i=0
开始,到i < len/2
结束(只需交换一半的字符即可完成整个字符串的反转)i
个字符与第len-i-1
个字符进行交换t
作为中间存储,完成两个字符的交换操作puts
函数输出反转后的字符串对于初始字符串"Hello":
len
为5i=0
和i=1
):
s[0]
(‘H’)与s[4]
(‘o’)交换s[1]
(‘e’)与s[3]
(‘l’)交换s[2]
(‘l’)不需要交换这种字符串反转方法的时间复杂度是O(n)(n为字符串长度),空间复杂度是O(1),属于高效的原地反转算法,不需要额外的存储空间来存放反转后的字符串。
需要注意的是,使用strlen
函数需要在代码开头添加#include
头文件。
int n = 1357;
char s[100];在数组中保存字符串"1357"
int main(void)
{
int input;
printf("请输入一个你要转换为字符的整数:\n");
scanf("%d",&input);
char s[100];
int i=0;
while(input!=0)
{
s[i]=input%10+'0';
input/=10;
++i;
}
s[i]='\0';
int len=strlen(s);
for(i=0;i
这段代码的功能是将用户输入的整数转换为对应的字符串并输出。
代码的核心逻辑分为两个主要步骤:
将整数拆分并存储为字符:
while
循环对输入的整数input
进行处理input%10
获取最后一位数字,然后加上'0'
将其转换为对应的字符(利用ASCII码的特性)input/=10
移除已经处理的最后一位数字s
中,索引i
递增反转字符数组:
len
for
循环交换对称位置的字符(第i
个和第len-1-i
个),实现整个字符串的反转'\0'
例如,如果用户输入整数12345
:
['5','4','3','2','1','\0']
['1','2','3','4','5','\0']
需要注意的是:
while(input!=0)
循环不会执行)strlen
函数需要包含#include
头文件如果要完善这段代码,需要添加对0和负整数的处理逻辑。