用strcpy替换数组的一部分
#include <stdio.h>
#include <string.h>
#define WORDS "beast"
int main()
{
char *orig = WORDS;
char copy[40] = "Be the best that you can be.";
puts(orig);
puts(copy);
strcpy(copy + 7, WORDS);
puts(copy);
return 0;
}
beast
Be the best that you can be.
Be the beast
strncpy(更安全)
strcpy 和strcat 都有一个安全漏洞
之前用strcpy做的示例程序里,目标数组很大可以容纳源字符串,所以没出错,我把目标数组改小
#include <stdio.h>
#include <string.h>
#define SIZE 40
#define LIM 5
char *s_gets(char *st, int n);
int main()
{
char temp[SIZE];
char target[LIM][LIM];
int i=0;
printf("Enter %d words beginning with q:\n", LIM);
while(i<LIM && s_gets(temp, SIZE)!= NULL)//一定要把i<LIM放在前面,这样第五个q开头的单词输入后就直接退出了,用短路运算符时一定把首要判断条件放在前面,顺序是需要考虑一下的哦
{
if(temp[0]!='q')// 等效于if(strncmp(temp, "q", 1))
{
puts("This word is not beginning with q!");
}
else
{
if(i!=4)
puts("Got one! Keep entering:");
strcpy(target[i], temp);
i++;
}
}
printf("End of entering. The input words beginning with q:\n");
for(i=0;i<LIM;i++)
puts(target[i]);
return 0;
}char *s_gets(char *st, int n)
{
char *ret_val;
int i=0;
ret_val = fgets(st, n, stdin);
if(ret_val)
{
while(*(st+i)!='\n' && st[i]!='\0')
i++;
if(st[i]=='\n')
st[i] = '\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
输出呈现这种错误,这是因为:
输入question太长了,临时数组长度为40,存的下,但是复制给目标数组时,目标数组长度只有5,所以只复制了前5个字符,没有复制到空字符,第二个quarter又是如此····
输出时,puts没有遇到空字符,就无法正确识别字符串结尾,于是输出了第一次遇到空字符前的所有字符,第二次输入也是如此,只是开始的位置变成了数组第二个元素的地址
Enter 5 words beginning with q:
question
Got one! Keep entering:
quarter
Got one! Keep entering:
quality
Got one! Keep entering:
queen
Got one! Keep entering:
query
End of entering. The input words beginning with q:
questquartqualiqueenquery
quartqualiqueenquery
qualiqueenquery
queenquery
query
用strncpy
if(i!=4)
puts("Got one! Keep entering:");
strncpy(target[i], temp, LIM-1);
target[i][LIM-1]='\0';
Enter 5 words beginning with q:
quarter
Got one! Keep entering:
quality
Got one! Keep entering:
question
Got one! Keep entering:
queen
Got one! Keep entering:
quote
End of entering. The input words beginning with q:
quar
qual
ques
quee
quot
sprintf
sprint 把数据写入字符串,多以可以把很多项(包括数字和字符串)合并为字符串
printf写入屏幕
sprintf第一个参数是目标字符串的地址,其余参数和printf相同,也是格式字符串和待写入项列表
#include <stdio.h>
#include <string.h>
#define MAX 10
char *s_gets(char *st, int n);
int main()
{
char first[MAX], last[MAX], all[MAX*2+20];
double prize;
puts("Enter your first name:");
s_gets(first, MAX);
puts("Enter your last name:");
s_gets(last, MAX);
puts("Enter your prize:");
scanf("%lf", &prize);//注意scanf输入double用%lf,输出double用%f
sprintf(all, "%s %s $%.2f\n", last, first, prize);
puts(all);
return 0;
}
char *s_gets(char *st, int n)
{
char *ret_val;
int i=0;
ret_val = fgets(st, n, stdin);
if(ret_val)
{
while(*(st+i)!='\n' && st[i]!='\0')
i++;
if(st[i]=='\n')
st[i] = '\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
Enter your first name:
galler
Enter your last name:
mary
Enter your prize:
1000
mary galler $1000.00
字符串函数总结
示例 字符串排序 strcm 选择排序算法 交换指针!!!
这个程序的巧妙之处是它通过交换指针实现排序
#include <stdio.h>
#include <string.h>
#define LIM 10
#define SIZE 40
char *s_gets(char *st, int n);
//void st_sort(char st[][SIZE], int n);
void st_sort(char *st[], int n);//指针数组的形式表示字符串数组
int main()
{
unsigned int ct=0;
unsigned int i;
char *ptr;
char st[LIM][SIZE];//字符串数组就是二维数组
char *ptstr[LIM];//[]优先级高于*,ptstr先和[]结合,所以ptstr是一个数组,
//又和前面的*结合,成为指针数组,即元素是指针
printf("Please enter up to %d lines, and I will sort them.\n", LIM);
puts("Press the enter key to stop.");
//最首要的判定条件放在最前面,即ct<LIM
//s_gets会把换行符替换为空字符,所以如果不输满LIM个字符,按下换行符就退出
while(ct<LIM && (ptr=s_gets(st[ct], SIZE))!=NULL && st[ct][0]!='\0')
{
ptstr[ct] = st[ct];//把每个输入的字符串的地址存在指针数组中
ct++;
}
st_sort(ptstr, ct);
//输出排序后的字符串
puts("The sorted strings:");
for(i=0;i<ct;i++)
puts(ptstr[i]);
return 0;
}
char *s_gets(char *st, int n)
{
char *ret_val;
int i=0;
ret_val = fgets(st, n, stdin);
if(ret_val)
{
while(*(st+i)!='\n' && st[i]!='\0')
i++;
if(st[i]=='\n')
st[i] = '\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
//void st_sort(char st[][SIZE], int n)//数组法表示形参
void st_sort(char *st[], int n)
{
unsigned int top, seek;
char *temp;
for(top=0;top<n-1;top++)
{
for(seek=top+1;seek<n;seek++)
{
if(strcmp(st[top], st[seek])>0)//大于0则st[top]应排在st[seek]后面
{
temp = st[top];
//交换指针!!!
st[top] = st[seek];//如果用数组法表示形参,这句代码错误,数组和数组不可直接赋值,但是指针形参使得编译器认为他们都是指针,可以赋值
st[seek] = temp;
}
}
}
}
可以看到,strcmp的返回值的正负性特别有用,使得我们的字符串排序变得极其轻松
不过,写程序时,我发现自己的问题:
- 写关系表达式易错,本题是按下换行符则停止输入,我之前写成st[ct][0]==’\0’,结果程序不进去循环,我调试发现前两个表达式都没问题才发现自己写错了。易错
- 排序算法中由于交换值会涉及到数组和数组之间的赋值,这在数组的使用规定中是不允许的,所以必须用指针法表示形参
- 函数原型和函数定义的形参形式要一致,要么都是数组法,要么就都是指针法,不可混用,否则无法通过编译,报错
Please enter up to 10 lines, and I will sort them.
Press the enter key to stop.
fdfk
uio
op
ih
oa
sdfg
The sorted strings:
fdfk
ih
oa
op
sdfg
uio
选择排序
这个排序算法我在草稿纸上推了,很简单,比如10个数字要从小到大排序:
3 6 1 2 7 0 9 4 8 5
首先top=0,st[top]=3,seek从1开始向右遍历,当seek=2时st[seek]更小,于是交换
1 6 3 2 7 0 9 4 8 5
top还是0,seek=3,直到seek=5再次达到交换条件
0 6 3 2 7 1 9 4 8 5
······
所以第一次内层循环最多交换n-1次
而第二次内层循环,top=1,则最多交换n-2次
top=n-2时,最多交换一次
(top取值范围:0—n-2,seek取值范围:top+1—n-1)
所以最多交换次数:
1
+
2
+
3
+
⋯
+
n
−
1
=
n
(
n
−
1
)
2
1+2+3+\cdots+n-1=\frac{n(n-1)}{2}
1+2+3+⋯+n−1=2n(n−1)
示例 计算标点符号个数(用到ctype.h中的函数)
toupper
ispunct是ctype.h中的函数
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define LIMIT 101
void ToUpper(char *st);
unsigned int PunctCount(const char *);
int main()
{
char line[LIMIT];
char *find;
puts("enter a line.");
fgets(line, LIMIT, stdin);
find = strchr(line, '\n');//查找换行符,如果找到了,就返回换行符的地址,否则返回空指针
if(find)//空指针的值是0
*find = '\0';//用空字符替换换行符
ToUpper(line);
puts(line);
printf("That line has %u punctuation characters.\n", PunctCount(line));
return 0;
}
void ToUpper(char *st)
{
while(*st)//不是空字符则进入循环
{*st = toupper(*st);
st++;}
}
unsigned int PunctCount(const char *st)
{
unsigned int n=0;
while(*st)
{
if(ispunct(*st))
n++;
st++;
}
return n;
}
这个程序值得学习的地方是while(*st)和if(find),利用了空字符的指针的值是0
enter a line.
I'm trying to calculate the number of punctuation characters, and can you hele me?
I'M TRYING TO CALCULATE THE NUMBER OF PUNCTUATION CHARACTERS, AND CAN YOU HELE ME?
That line has 3 punctuation characters.
如果#define LIMIT 81则
enter a line.
I'm trying to calculate the number of punctuation characters, and can you hele me?
I'M TRYING TO CALCULATE THE NUMBER OF PUNCTUATION CHARACTERS, AND CAN YOU HELE M
That line has 2 punctuation characters.
给main函数带参数
示例1 输出参数和参数的个数
这个示例是在命令行执行,输出参数的个数和参数
参数的个数是操作系统检测到后赋给main的参数argc的(c是count的缩写),OS还把所有参数都赋给了main的指针数组参数,即把所有参数的地址发给了main函数
#include <stdio.h>
int main(int argc, char *argv[])
{
int count;
printf("The command line has %d arguments:\n", argc-1);
for(count=1;count<argc;count++)
printf("%d: %s\n", count, argv[count]);
printf("\n");
return 0;
}
直接在编译器中执行,不行,因为无法输入参数
The command line has 0 arguments:
Process returned 0 (0x0) execution time : 0.597 s
Press any key to continue.
在命令行执行,可以输入参数
C:\Users\wulimmya>cd C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug
C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC Resistance is futile
The command line has 3 arguments:
1: Resistance
2: is
3: futile
示例2 把命令行参数字符串转换为数字
这里说的是把键盘输入的数字,实际是一个个字符组成的字符串,把他们转换为数值形式,才可以用于程序的计算
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int i, times;
if(argc<2 || (times=atoi(argv[1]))<1)
printf("Usage: %s positive-number\n", argv[0]);
else
for(i=0;i<times;i++)
puts("Hello, good looking!");
return 0;
}
atoi函数把字符串转换为int类型的整数
C:\Users\wulimmya>cd C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug
C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC 3
Hello, good looking!
Hello, good looking!
Hello, good looking!
C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC 1
Hello, good looking!
C:\Users\wulimmya\Documents\MyCCode\MyC\bin\Debug>MyC
Usage: MyC positive-number
#include <stdio.h>
#include <stdlib.h>
#define LIM 30
char *s_gets(char *st, int n);
int main()
{
char number[LIM];
char *end;
long value;
puts("Enter a number (empty line to quit):");
while(s_gets(number, LIM) && number[0]!='\0')
{
value = strtol(number, &end, 10);
printf("base 10 input, base 10 output:%ld, stopped at %s (%d)\n",
value, end, *end);
value = strtol(number, &end, 16);
printf("base 16 input, base 10 output: %ld, stopped at %s (%d)\n",
value, end, *end);
puts("Next number:");
}
puts("Bye!");
return 0;
}
char *s_gets(char *st, int n)
{
char *ret_val;
int i=0;
ret_val = fgets(st, n, stdin);
if(ret_val)
{
while(*(st+i)!='\n' && st[i]!='\0')
i++;
if(st[i]=='\n')
st[i] = '\0';
else
while(getchar()!='\n')
continue;
}
return ret_val;
}
Enter a number (empty line to quit):
4
base 10 input, base 10 output:4, stopped at (0)
base 16 input, base 10 output: 4, stopped at (0)
Next number:
45
base 10 input, base 10 output:45, stopped at (0)
base 16 input, base 10 output: 69, stopped at (0)
Next number:
10atom
base 10 input, base 10 output:10, stopped at atom (97)
base 16 input, base 10 output: 266, stopped at tom (116)
Next number: