字符串
以空字符 ‘\0’ 结尾的char类型数组
函数传首字符地址指针,通过空字符确定结束
不同类型的0
空字符:
‘\0’ 标记字符串结尾,对应字符编码是0,
整数类型,占1字节 eg:"
"
占
2
字节
,
′
" 占2字节,'
"占2字节,′'占1字节
空指针:
NULL,有一个值,不会和任何数据的有效地址对应,
指针类型,占4字节,
通常用于返回有效地址表示特殊情况发生,
eg,遇到文件结尾或者未能按预期执行
#include <stdio.h>//puts
#define MSG "I'm special"
#define MAXLENGTH 81
char words[MAXLENGTH] = "I am a string in an array.";
const char *pt1 = "Something is pointing at me .";
puts("Here are some strings :"); // 只显示字符串,且自动加上换行符
puts(MSG);
puts(words);
puts(pt1);
words[8] = 'p';
puts(words);
定义
字符串常量 字符字面量
字符串:双引号括起来的字符和(编译器自动加入末尾的)'\0’字符
作为可执行文件的一部分存储在数据段中
载入程序时载入字符串
存储在静态存储区,只会被存储一次
char greeting[50] = "Hello,and"" how are"" you"
" today !";
/*即"Hello, and how are you today ! ";
字符串字面量之间没有间隔,或者空白字符分隔,等同于串联起来的字符串字面量*/
printf("\"Run,Spot,run !\" exclaimed Dick.\n");
/*如果要在字符串内部使用双引号,必须在双引号前面加上一个反斜杠(\)
* 输出如下:"Run,Spot, run ! " exclaimed Dick.*/
printf("%s,%p, %c\n", "we", "are", *"space farers");
/*输出 we,0x100000f61,s
%p 打印字符串首字符的地址,双引号括起来的内容相当于指向该字符串存储位置的指针
%c *"space farers"表示字符串指向地址上存储的值,即首字符s */
字符串数组和指针
必须让编译器知道需要多少空间
字符数组有空间,有副本
字符指针只存字符串常量的地址
const char m1[40] = "one line's worth.";
/*const表明不会更改这个字符串、
数组元素个数至少比字符串长度多1('\0')、所有未被使用的元素都被自动初始化为'\0'
相当于const char m1[40] = {'o', 'n', 'e', ' ', 'l', 'i', 'n', 'e', '\'','s', ' ', 'w', 'o', 'r', 't', 'h', '.', '\0'};
有'\0'即为字符串,无'\0'即为字符数组
*/
const char m2[] = "If you can't think of anything, fake it.";
/*省略大小,编译器自动计算,查找末尾的空字符
* 只可在初始化使用,稍后填充的数组,声明时必须指定大小*/
char cookies[1];// 有效
char cakes[2 + 5];// 有效,数组大小是整型常量表达式
char pies[2 * sizeof(long double) + 1]; // 有效
int n = 8;
char crunbs[n]; // 在C99标准之前无效,C99标准之后这种数组是变长数组
// 字符数组名和其他数组名一样,是该数组首元素的地址。
char car[10] = "Tata";
// car == &car[0];
// *car == 'T';
// *(car + 1) == car[1] == 'a';
char ar[] = MSG;
/* char ar[]="I'm special";
* 开始运行时在内存中分配一个内含12(11+1'\0')个元素的数组,把字符串拷到数组中,每个元素被初始化为对应的字符
* 字符串有两个副本,静态内存的字符串字面量,存储在ar1数组中的字符串
* ar:数组首元素的别名,地址常量,不可以对ar赋值,指向别处无法访问该字符串,不可以++ --
* 因为是拷贝,所以数组可以是const也可以不是const修饰
*
* ar[1]、*(ar + 1)、 不可以*(ar++);
* ar = pt 指向别处无法访问该字符串
* ar1[7] = 'M'、*(ar1 + 7) = 'M'、修改的是拷贝的副本,数组名是常量,数组元素是变量(除非const) */
const char *pt = MSG;
/* 指针表示法创建字符串,双引号内容决定预留空间
* 运行时把字符串地址存储在指针变量,指向字符串首字符
* 指针值可改变,可被赋值,++指向第二个字符,pt[1],*(pt+1),*(pt++),pt=ar
* 因为是指向,字符串常量为const,pt1也应该是指向const的指针,不可以通过指针改变字符串,指针可以指向其他位置
* 通过指针改变字符串常量会内存错误,pt[3]='F' 会导致所有引用MSG都变 */
printf("address of \"I'm special\": %p\n", "I'm special");
printf("address ar: %p\n", ar); // 拷贝一份到ar,两份地址不同
printf("address pt : %p\n", pt); // 和字符串位置相同,pt指向字符串首字符
printf("address of MSG: %p\n", MSG); // 只替换,地址相同
printf("address of \"I'm special\": %p\n", "I'm special");
// 多次使用的相同字面量存储在一处或多处,更改一处可能会影响所有使用该字符串的代码
const char *mesg = "Don't be a fool!";
const char *copy;
copy = mesg; // while(mesg==copy) 判断两个指针是否指向同一位置
printf("%s \n", copy);
printf("mesg = %s; &mesg = %p; value = %p\n", mesg, &mesg, mesg);
printf("copy = %s; © = %p; value = %p\n", copy, ©, copy);
/* 输出
mesg = Don't be a fool!; &mesg = 0x0012ff48; value = 0x0040a000
copy = Don't be a fool!; © = 0x0012ff44; value = 0x0040a000
第二项:指针的地址,每个指针4字节
第三项:指针指向的地址,都指向同一个字符串,并未拷贝
*/
字符串二维数组
#define SLEN 40
#define LIM 5
const char *mytalents[LIM] = {
"Adding numbers swiftly",
"Multiplying accurately",
"Stashing data",
"Following instructions to the letter",
"Understanding the C language"};
/* 5个字符串
* mytalents[0]表示第一个字符串
* mytalents[1][2]表示第2个字符串的第3个字符
* 内含5个指针的数组,在系统中占5*8=40字节
* 字符串都被存在静态存储区,不可以通过指针修改字符串
* 不规则数组,每个指针指向的字符串不必存储在连续的内存中
* 效率高
* */
char yourtalents[LIM][SLEN] = {
"Walking in a straight line",
"Sleeping",
"Watching television",
"Mailing letters",
"Reading email"};
/* 内含5个数组的数组,每个数组内含40个char类型的值,共占用200字节
* 数组存储字符串字面量的副本,可以更改内容,会为字符串预留空间
* 规则数组,每个元素大小必须相同,是能储存最长字符串的大小
*/
int i;
puts("Let's compare talents. ");
printf("%-36s %-25s\n", "My Talents", "Your Talents");
for (i = 0; i < LIM; i++)
printf("%-36s %-25s\n", mytalents[i], yourtalents[i]);
printf("\nsizeof mytalents: %zd,sizeof yourtalents: %zd\n", sizeof(mytalents), sizeof(yourtalents));
输入
输入之前先分配空间
gets
超出长度擦写现有数据、不安全
换行符结束
#define STLEN 81
char words[STLEN];
puts("Enter a string, please.");
gets(words);
/*典型用法,整行除了\n,都读入
不检测输入长度,输入过长导致缓冲区溢出,会擦写掉其他的数据,访问时会报分段错误 segmentation fault
部分编译器(C99)会报 unsafe,C11不支持
可以#define STLEN 5 尝试错误*/
printf("Your string twice : \n");
printf("%s \n", words);
puts(words);
puts("Done.");
fgets fputs
fgets:因为存换行符,通常和fputs配对
#define SALEN 14
char words[SALEN];
puts("Enter a string, please.");
fgets(words, SALEN, stdin);
/* 读入字符串存入words
* 读入字符的最大数量SALEN,SALEN-1个字符(末尾加\0)或者到第一个换行符结束(存\n\0)
* 读入的文件,从键盘stdin */
printf("Your string twice(puts(),then fputs()):\n");
puts(words); // puts会自动加上换行符,加上原本fgets的换行符
fputs(words, stdout);
/* fgets原本的换行符,不加多余换行
* 从文件输出,屏幕输出stdout
* 返回指向char的指针,返回地址与传入的第一个参数相同
* 读到文件结尾就返回一个特殊的指针 空指针NULL 保证不会指向有效的数据*/
puts("Done.");
//原样打印输入
while (fgets(words, SALEN, stdin) != NULL && words[0] != '\n')
{ /*读到的字符串不为空,且第一个字符不是换行符,一直输出
使用缓冲I/O,用户按下return之前,输入都在临时缓冲区,按下之后在输入中增加一个换行符,整行发给fgets
fputs输出把字符发送给另一个缓冲区,换行符之后发送至屏幕*/
puts(words);
}
//取数组正确输入,不要\n
int i;
puts("Enter strings (empty line to quit): ");
while (fgets(words, SALEN, stdin) != NULL && words[0] != '\n')
{
i = 0;
while (words[i] != '\n' && words[i] != '\0')
// 遍历直到遇到换行或空格
i++;
if (words[i] == '\n') // 先遇到换行
words[i] = '\0'; // 替换换行符
else // 先遇到空格丢掉剩余部分,避免下次读取错误
while (getchar() != '\n')
// 读取但不储存输入,包括\n
continue;
puts(words);
puts("done");
}
gets_s
gets_s (words,STLEN);
只从标准输入中读数据
读到换行符丢弃
超过最大字符数:目标数组首字符设为空字符,读取并丢弃随后的输入直到换行符或文件结尾,然后返回空指针,调用依赖实现的处理函数或者选择的其他函数
s_gets
处理fgets 换行符问题
char *s_gets(char *st, int n)
{//读一行最多n个,去掉\n
char *ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val) // 即,ret_val != NULL
{
while (st[i] != '\n' && st[i] != '\0')
i++;
if (st[i] == '\n')
st[i] = '\0'; // 替换换行
else
while (getchar() != '\n')
continue;
/*只读n-1个字符,空字符结尾,丢弃剩余
避免留在缓冲区导致下一次读取错误*/
}
return ret_val;
}
scanf
获取单词
从第一个非空白字符作为字符串开始
%s 以下一个空白字符作为字符串结束
%10s 读取10个字符或者到第一个空白字符
剩余字符留在缓冲器等待下一次读取
返回读取成功的项或者EOF(文件结尾)
数据行过长也会溢出,字段宽度可以防止溢出
典型用法:读取并转换混合数据类型为某种标准形式
char name1[11], name2[11];
int count;
printf("Please enter 2 names. \n");
count = scanf("%5s %10s", name1, name2);
printf("I read the %d names %s and %s.\n", count, name1, name2);
输出
puts
字符串地址作为参数传递
自动加换行符,和丢弃换行符的gets配对
遇到空字符 ‘\0’ 停止输出
/* put_out.c --使用puts () */
#define DEF "I am a #defined string . "
char str1[80] = "An array was initialized to me.";
const char *str2 = "A pointer was initialized to me.";
puts("I'm an argument to puts().");
puts(DEF);
puts(str1);
puts(str2);
puts(&str1[5]); // 字符串第6个字符开始打印
puts(str2 + 4); // 字符串第5个字符开始打印
char side_a[] = "Side A";
char dont[] = {'w', 'o', 'w', '!'};
char side_b[] = "side B";
puts(dont);
/* dont不是一个字符串,缺少表示结束的空字符,
puts不知道在何处停止,会一直打印后面内存的内容,直到遇见空字符*/
fputs
第二个参数指明要写入数据的文件,stdout
不会在输出末尾添加换行符,和保留换行符的fgets配对
char line [81] ;
while (gets(line) )//与while (gets (line)!= NULL)相同
puts(line);//加换行
char line [81];
while (fgets (line,81,stdin) )//存换行
fputs(line, stdout);
printf
字符串地址传参
格式化不同数据类型
需要指明换行符
printf("%s\n", string); // 相当于puts(string) ;
printf("well,%s,%s \n", name, MSG);
自定义输入输出函数
在getchar()和putchar()基础上自定义所需函数
int put2(const char *string); // 打印不要\n,记数
put2("If I'd as much money");
put2(" as I could spend, \n");
printf("I count %d characters. \n", put2("I never would cry old chairs to mend."));
int put2(const char *string)
{/*不会改变字符串,使用const
char sting[]:实参是数组,
char *string:实参可以是数组名,双引号字符串,char * 变量
一般传参不需要长度,以空字符结尾*/
int count = 0;
while (*string)
{ // *string!='\0' string[i]!='\0' 指向空字符值为0
putchar(*string++);
count++;
/* *string++ 相当于 *(string++),输出*string ,string++递增指针指向下一个字符,相当于string[i++]
++*string,*string,H,然后++,G
*/
}
return count;
}
string.h
字符串处理函数
const char * s作为函数参数:该字符串不会被该函数更改
restrict :修饰限制
strlen
size_t strlen (const char * s) ;
返回s字符串中的字符数,不包括空字符。
#include <string.h>/*内含宇符串函数原型*/
void fit (char *, unsigned int);
char mesg[] = "Things should be as simple as possible,"
"but not simpler.";
puts(mesg);
fit(mesg, 38);
puts(mesg); // 遇到空字符停止
puts("Let 's look at some more of the string.");
puts(mesg + 39); // 打印剩下的部分
void fit(char *string, unsigned int size)
{
if (strlen(string) > size)
string[size] = '\0'; // 超出部分替换为空字符 string[38]='\0'
}
strcat strncat
strcat
char *strcat(char * restrict s1,const char * restrict s2);
把s2的备份(包括空字符)附加在s1末尾,作为s1,不更改s2
s2的第一个字符覆盖s1的空字符
返回s1首地址
不检测长度,如果相加长度超过第一个字符串的长度则报错,错误可避免
可以用strlen(),计算长度并判断,拼接后的字符串长度加1 用于存放末尾的空字符
strncat
char *strncat(char *restrict s1,const char *restrict s2,size_t n);
n:指定最大添加字符数
最大长度或者空字符时停止,最后均会自动添加空字符
#define SIZE 30
#define BUGSIZE 13
char *s_gets(char *st, int n);
char flower[SIZE];
char addon[] = "s smell like old shoes. ";
char bug[BUGSIZE];
int available;
puts("what is your favorite flower?");
s_gets(flower, SIZE);
if ((strlen(addon) + strlen(flower) + 1) <= SIZE)
strcat(flower, addon);//相加长度超了会出错,先判断长度
puts(flower);
puts(addon);//strcat不影响第二个参数
puts("what is your favorite bug?");
s_gets(bug, BUGSIZE);
available = BUGSIZE - strlen(bug) - 1;
strncat(bug, addon, available);
puts(bug);
strcmp strncmp
strcmp
int strcmp(const char * sl, const char s2) ;
比较两个字符串参数,相同返回0,否则返回非零值(ASCII值s1-s2)
即使数组长度不一样,只比较第一个空白字符前面的字符串
字符实际是整数类型,可以直接比较,不可作为strcmp的参数
strncmp
int strncmp(const char * s1,const char * s2, size_t n) ;
只比较前n个字符或者第一个空字符之前
#define ANSWER "Grant"
#define LIM_10 10
#define STOP "quit"
#define LISTSIZE 6
char try[SIZE];
puts("who is buried in Grant's tomb? ");
s_gets(try, SIZE);
// while (try !=ANSWER)//两个字符串地址是否相同
while (strcmp(try, ANSWER) != 0)
// 比较字符串内容 while(strcmp(try,ANSWER))
{
puts("No,that 's wrong. Try again.");
s_gets(try, SIZE);
}
puts("That's right!");
printf("strcmp (\"A\",\"A\") is %d\n", strcmp("A", "A"));
printf("strcmp (\"A\",\"B\") is %d\n", strcmp("A", "B"));
// ASCII排序ASTOP<B 则A-B<0 ASCII 差值为-1
printf("strcmp (\"B\",\"A\") is %d\n", strcmp("B", "A"));
// ASCII排序A<B 则B-A>0 ASCII 差值为1
printf("strcmp (\"C\",\"A\") is %d\n", strcmp("C", "A"));
// ASCII排序A<C 则C-A>0 ASCII 差值为2
printf("strcmp (\"Z\", \"a\") is %d\n", strcmp("Z", "a"));
// ASCII排序Z<a 则Z-a<0 ASCII 差值为-7 大写在小写前面
printf("strcmp (\"apples\",\"apple\") is %d\n" ,strcmp("apples", "apple"));
/*113 依次比较每个字符,直到发现第一对不同的字符为止,
空字符在ASCII排第一最小*/
char input[LIM_10][STLEN];
int ct = 0;
printf("Enter up to %d lines (type quit to quit):\n", LIM_10);
while (ct < LIM_10 && s_gets(input[ct], STLEN) != NULL &&
strcmp(input[ct], STOP) != 0)
ct++;
/*输入项达到LIM_10、读到EOF字符、输入quit时退出*/
printf("%d strings entered\n", ct);
// while (ct < LIM_10 && s_gets(input[ct], STLEN) != NULL && input[ct][0] != '\0')
// /*输入项达到LIM_10、读到EOF字符、换行时退出
// *输入空行时,s_gets会把该行第一个字符(换行符)替换成空字符*/
//strncmp
const char *list[LISTSIZE] =
{
"astronomy", "astounding",
"astrophysics", "ostracize",
"asterism", "astrophobia"};
int count = 0;
int i;
for (i = 0; i < LISTSIZE; i++)
if (strncmp(list[i], "astro", 5) == 0) // 只比较前5个字符
{
printf("Found : %s \n", list[i]);
count++;
}
printf("The list contained %d words beginning with astro. \n",count);
strcpy strncpy
strcpy
char *strcpy(char * restrict s1,const char * restrict s2);
拷贝整个s2(包括空字符)到s1,s2不变
必须在拷贝之前确认目标字符串有足够空间容纳源字符串的副本
s1:指向数据对象,并有足够空间;不必指向数组的开始,可以用于拷贝数组的一部分
s2:指针、数组名、字符串常量
返回s1的首地址
strncpy
char *strncpy(char *restrict s1, const char *restrict s2,size_t n);
n:可拷贝的最大字符数
拷贝s2的前n个字符(不拷贝空字符)或者空字符之前的字符(拷贝空字符)
一般把n设置为目标数组的长度-1,最后一个元素设置为空字符,确保拷贝前n个字符时存储的是一个字符串
#define TARGSIZE 7
#define WORDS "beast"
char qwords[LIM][SLEN];
char temp[SLEN];
int i = 0;
printf("Enter %d words beginning with q: \n", LIM);
while (i < LIM && s_gets(temp, SLEN))
{
if (temp[0] != 'q')
/*首字母不为q 时不存,不递增
if (strncmp (temp, "q",1)!= 0)
*/
printf("%s doesn't begin with q! \n", temp);
else
{
strcpy(qwords[i], temp);
/*把temp的字符串拷贝到qwords[i]
qwords[i]=temp 只拷贝地址,且语法错误
temp="Solong";语法错误
*/
// strncpy(qwords[i], temp, TARGSIZE - 1);
// qwords[i][TARGSIZE - 1] = '\0';//只拷6个,末尾+\0
i++;
}
}
puts("Here are the words accepted : ");
for (i = 0; i < LIM; i++)
puts(qwords[i]);
const char *orig = WORDS;
char copy[SLEN] = "Be the best that you can be . ";
char *ps;
puts(orig);
puts(copy);
ps = strcpy(copy + 7, orig);
/*把orig拷贝到copy数组的第8个字符位置开始
orig的空字符同样拷贝到copy,打印的时候遇到空字符结束
返回第一个参数的值,第8个字符开始
*/
puts(copy);
puts(ps);
sprintf
stdio.h
把输入格式化为标准格式,写入字符串
第一个参数:目标字符串地址
其余参数和printf()相同:格式字符串,待写入项的列表
#define MAX 10
char first[MAX];
char last[MAX];
char formal[2*MAX + 10];
double prize;
puts("Enter your first name : ");
s_gets(first, MAX);
puts("Enter your last name : ");
s_gets(last, MAX);
puts("Enter your prize money : ");
scanf("%lf", &prize);
sprintf(formal, "%s,%-19s: $%6.2f\n", last, first, prize);
puts(formal);
memcpy memmove
void *memcpy(void *restrict s1, const void *restrict s2, size_t n);
void *memmove(void *s1, const void *s2,size_t n);
/strcpy复制字符数组,memcpy和memmove复制任意类型的数组
s2指向的位置拷贝n字节到s1指向的位置,返回s1,restrict修饰说明不能有重叠区域/
#define SIZE_10 10
void show_array(const int ar[], int n); // 如果编译器不支持C11的 ,可以注释掉下面这行
_Static_assert(sizeof(double) == 2 * sizeof(int), "double not twice int size");
//断言,编译器检查double不等于2倍int大小时,编译不通过并报错
// mems.c--使用memcpy()和memmove()
int values[SIZE_10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int target[SIZE_10];
double curious[SIZE_10 / 2] = {2.0, 2.0e5, 2.0e10, 2.0e20, 5.0e30};
puts("memcpy() used:");
puts("values (original data):");
show_array(values, SIZE_10);
memcpy(target, values, SIZE_10 * sizeof(int));
puts("target (copy of values):");
show_array(target, SIZE_10);
puts("\nUsing memmove()with overlapping ranges:");
memmove(values + 2, values, 5 * sizeof(int));
puts("values--elements 0-4 copied to 2-6:");
show_array(values, SIZE_10);
puts("\nUsing memcpy()to copy double to int:");
memcpy(target, curious, (SIZE_10 / 2) * sizeof(double));
/* 从curious拷贝5个double大小的数据到target 只负责拷贝不关心数据类型,不会做类型转换*/
puts("target--5 doubles into 10 int positions:");
show_array(target, SIZE_10 / 2);
show_array(target + 5, SIZE_10 / 2);
void show_array(const int ar[], int n)
{
int i;
for (i = 0; i < n; i++)
printf("%d ", ar[i]);
putchar('\n');
}
其他
char *strchr (const char * s, int c) ;
如果s字符串中包含c字符,该函数返回指向s字符串首位置的指针(末尾的空字符也是字符串的一部分,所以在查找范围内);
如果在字符串s中未找到c字符,该函数则返回空指针。
char *strrchr(const char * s, int c);
该函数返回s字符串中c字符的最后一次出现的位置(末尾的空字符也是字符串的一部分,所以在查找范围内)。
如果未找到c字符,则返回空指针。
char *strpbrk (const char * s1,const char * s2);
如果s1字符中包含s2字符串中的任意字符,该函数返回指向s1字符串首位置的指针;
如果在s1字符串中未找到任何s2字符串中的字符,则返回空字符。
char *strstr (const char * sl,const char * s2) ;
该函数返回指向s1字符串中s2字符串出现的首位置。如果在s1中没有找到s2,则返回空指针。
字符串排序
#define LIM_20 20 /*可读入的最多行数*/
#define HALT "" /*空字符串停止输入*/
void stsrt(char *strings[], int num); /*字符串排序函数*/
char input[LIM_20][STLEN]; // STLEN 限制字符串长度,包括\0
/*储存输入的数组,可存20个内含80个字符的字符串*/
char *ptstr[LIM_20];
/*指针数组,可存放20个指针,每个指针指向字符串首地址
只比较首字母
*/
int ct = 0; /*输入计数*/
int k; /*输出计数*/
printf("Input up to %d lines,and I will sort them.\n", LIM_20);
printf("To stop, press the Enter key at a line's start.\n");
while (ct < LIM_20 && s_gets(input[ct], STLEN) != NULL && input[ct][0] != '\0')
{
ptstr[ct] = input[ct]; /*指针指向字符串首字符*/
ct++;
}
stsrt (ptstr,ct) ;/*字符串排序函数,指针交换,并不修改input*/
puts("\nHere's the sorted list : \n");
for (k = 0; k < ct; k++)
puts(ptstr[k]);
/*排序后的指针*/
/*字符串-指针-排序函数*/
void stsrt(char *strings[], int num)
{ /*选择排序,每次循环和首元素比较,挑出最小的排在最前
for n=首元素至n=倒数第2个元素
{//找出剩余元素中的最小值,并将其放在第n个元素中
for m第n+1个元素至最后一个元素,
比较第m个元素与第n个元素,如果第m个元素更小,交换这两个元素的值
}*/
char *temp;
int top, seek;
for (top = 0; top < num - 1; top++)
for (seek = top + 1; seek < num; seek++)
if (strcmp(strings[top], strings[seek]) > 0)
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
ctype.h
字符处理函数
#include <string.h> //strchr
#include <ctype.h> //toupper ispunct
void ToUpper(char *str);
int PunctCount(const char *str);
char line[STLEN];
char *find;
puts("Please enter a line : ");
fgets(line, STLEN, stdin);
find = strchr(line, '\n'); // 查找换行符
if (find)// 如果地址不是NULL,
*find = '\0'; // 用空字符替换
ToUpper(line);
puts(line);
printf("That line has %d punctuation characters.\n", PunctCount(line));
void ToUpper(char *str)
{
while (*str)
{// 遇到空字符停止 while(islower(*str)) 是小写返回真
*str = toupper(*str); // 字符转换为大写,
str++;
}
}
int PunctCount(const char *str)
{
int ct = 0;
while (*str)
{
if (ispunct(*str)) // 统计标点符号个数
ct++;
str++;
}
return ct;
}
命令行参数
命令行:在命令行环境中,为运行程序输入命令的行
命令行参数是同一行的附加项,用于传参
不同集成环境输入参数方式不同
双引号括起来的多个单词为一个参数
#include <stdio.h>
int main(int argc, char *argv[])
{/*编译为可执行文件repeat 调用: repeat Resistance is futile
argc :参数(命令行单词)数量 ,4
argv:字符串参数列表,参数从1开始存(大部分系统),每个指针指向字符串开始*/
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]); // argv[0]指向repeat
printf("\n");
return 0 ;
}
字符串转数字
数字可以以字符串形式存储,以数值形式存储
数值形式用做数值运算,字符串形式用做屏幕显示
printf scanf
命令行参数被读取为字符串,转换为数字
#include <stdio.h>
#include <stdlib.h> //atoi atof(转换为浮点数) atof(转换为long)
#define LIM 30
// long strtol(const char *restrict nptr, char *restrict endptr, int base);
// /*指向待转换字符串的指针,标识数字后字符的地址,进制,字符串转化为long
// strtoul 字符串转化为unsigned long
// strtod 字符串转化为double*/
int main(int argc, char *argv[])
{
//atoi转换,编译为hello,调用:hello 3
int i, times;
if (argc < 2 || (times = atoi(argv[1])) < 1)
/*只有命令没有参数、或者参数转化为整数<1
短路或,第一个条件成立才判断第二个
atoi 把字符串开头的整数转换为整数,没有整数返回0*/
printf("Usage : %s positive-number\n", argv[0]);
else
for (i = 0; i < times; i++)
puts("Hello, good looking!");
//strtol转换
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); /*十进制转化number里的数字,数字返回给value,数字后的字符地址赋值给end*/
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 ! \n");
}
return 0;
}