⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c.txt

📁 有关C语言中字符串的操作的一些经典程序
💻 TXT
📖 第 1 页 / 共 5 页
字号:

9        strcpy(string, str1);

10   }

题(3)

1    void test3(char* str1)

2    {

3        char string[10];

4        if(strlen(str1) <= 10)

5        {

6            strcpy(string, str1); 

7        }

8    }

解析

这3道题都有数组越界的问题。

q  题(1)中,string是一个含有10个元素的字符数组,str1指向的字符串长度为10,在进行strcpy调用时,会将str1的结束符也复制到string数组里,即复制的字符个数为11,这样会导致string出现数组越界。程序不一定会因此而崩溃,但这是一个潜在的危险。解决办法是将string的元素个数定义为11。

q  题(2)中,str1和string都是含有10个元素的字符数组,并且str1的元素全部被赋为字符“a”,然后再调用strcpy。这里会出现以下两个问题:一个问题是str1表示的字符数组没有以'\0'结束,在随后调用strcpy时无法判断什么时候复制结束;另一个问题是string的数组长度不够,出现数组越界的现象。解决办法是将string和str1的元素个数都定义为11个,并在调用strcpy之前加入一条语句把str1[10]赋为'\0'。

q  题(3)中,if语句使用小于等于“<=”进行比较,如果str1的长度等于10,也会出现数组越界的情况。解决办法是把“<=”换成“<”。

答案

3道题都有数组越界的问题。改正后的程序如下所示。

题(1)

1    void test1()

2    {

3        char string[11];           //字符数组长度为11,多分配一个

4        char* str1 = "0123456789";

5        strcpy(string, str1);

6    }

题(2)

1    void test2()

2    {

3        char string[11], str1[11];   //字符数组长度都为11,均多分配一个

4        int i;

5        for(i=0; i<10; i++)

6        {

7            str1[i] = 'a';

8        }

9        str1[10] = '\0';            //初始化str1为空字符串

10       strcpy(string, str1);

11   }

题(3)

1    void test3(char*str1)

2    {

3        char string[10];

4        if(strlen(str1) < 10)        //不能用<=

5        {

6            strcpy(string, str1); 

7        }

8    }

 

面试例题9:分析程序——数组越界。

考点:不当的循环操作导致数组越界。

出现频率:★★★

下面这个程序执行后会出现什么错误?

1    #define MAX 255

2    int main()

3    {

4        unsigned char A[MAX], i;

5    

6        for (i = 0; i <= MAX; i++)

7            A[i] = i;

8    }

解析

代码第6行的for循环中用的是“<=”,当i=MAX时数组越界。值得注意:这个程序很容易使人误认为只有数组越界的问题,但只要细心些就能发现,i是无符号的char类型,它的范围是0~255,所以“i<=MAX”一直都是真,这样会导致无限循环。可以把“i<=MAX”改为“i<MAX”,这样既避免了无限循环又避免了数组越界。

答案

i<=MAX导致数组越界以及无限循环,应改为i<MAX。

 

面试例题10:分析程序——打印操作可能产生数组越界。

考点:打印操作时可能产生的数组越界问题。

出现频率:★★★

下面这个程序的打印结果是什么?

1    #include <stdio.h>

2    

3    int main()

4    {

5        int a[5]={0, 1, 2, 3, 4}, *p;

6        p = a;

7        printf("%d\n",*(p + 4*sizeof(int)));

8

9        return 0;

10   }

答案

这个程序存在着越界的问题。

代码第6行,p指向a的第1个元素,所以p+4指向a的最后一个元素即4,p + 4 * sizeof(int)即p+16,此时指向的是数组a的第17个元素,显然已经越界了,因此打印结果是个随机数。

6.2.3  其他编程问题
由于字符串非常灵活,因此面试中非常注重字符串操作的考察。本节列出了一些经常出现的字符串考题,例如有关字符串长度检测,查找子串,单向翻转,判断是否回文等的题目。

 

面试例题11:编程实现字符串的长度检测。

考点:strcpy库函数的实现细节。

出现频率:★★★★★

解析

这个题目非常简单,字符串是以'\0'作为结束符,所以只需要做一次遍历就可以了。但是需要注意的是要尽量把程序写得简单高效。看下面的示例代码:

1    #include <stdio.h>

2    #include <assert.h>

3

4    int strlen1(const char* src)

5    {

6        assert( NULL != src);         //src必须有效

7        int len = 0;                  //保存src的长度

8        while(*src++ != '\0')           //遇到结束符'\0'退出循环

9            len++;                 //每循环一次len加1

10       return len;

11   }

12   

13   int strlen2(const char* src)

14   { 

15       assert( NULL != src);        //src必须有效

16       const char *temp = src;      //保存src首地址

17       while(*src++ != '\0');         //遇到结束符'\0'退出循环

18       return (src-temp-1);         //返回尾部指针与头部指针之差即长度

19   }

20   

21   int main()

22   {

23       char p[] = "Hello World!";

24       printf("strlen1 len: %d\n", strlen1(p));   //打印方法1得到的结果

25       printf("strlen2 len: %d\n", strlen2(p));   //打印方法2得到的结果

26   

27       return 0;

28   }

strlen1和strlen2这两个函数用来计算字符串长度。它们的区别如下所示。

q  strlen1用局部变量len在遍历的时候做自增,然后返回len。因此每当while循环一次,就需要执行两次自增操作。

q  strlen2用局部变量temp记录src遍历前的位置。while循环一次只需要一次自增操作,最后返回指针之间的位置差。

当字符串较长的时候strlen2比strlen1的效率更高。下面是程序的输出结果:

    strlen1 len: 12

    strlen2 len: 12

 

面试例题12:编程实现字符串中子串的查找。

考点:strstr库函数的实现细节。

出现频率:★★★★★

编写实现strstr即一个函数,即从一个字符串中,查找另一个字符串的位置,如strstr("12345", "34")返回值为2,即在2号位置找到字符串34。

解析

程序如下所示:

1    #include <stdio.h>

2    #include <assert.h>

3

4    const char *strstr(const char* src, const char* sub)

5    {

6        const char *bp;

7        const char *sp;

8    

9        if (src == NULL || NULL == sub) //判断src与sub的有效性

10       {

11           return src;

12       }

13       while (*src) //遍历src字符串

14       {

15           bp = src;                //用于src的遍历

16           sp = sub;               //用于sub的遍历

17           do 

18           {                       //遍历sub字符串

19               if (!*sp)            //如果到了sub字符串结束符位置

20                   return src;     //表示找到了sub字符串,退出

21           } while (*bp++ == *sp++);

22           src += 1;    

23       }

24   

25       return NULL;

26   }

27   int main()

28   {

29       char p[] = "12345";

30       char q[] = "34";

31   

32       char *r = strstr(p, q);

33       printf("r: %s\n", r);

34

35       return 0;

36   }

main函数中的测试结果为:

    r: 345

代码第32行调用strstr结束之后,r指向了数组p的第3个元素。这里strstr函数的方法是循环取src的子串与sub比较。以本题中的“12345”和“34”为例,比较步骤如下所示。

q  “12345”和“34”比较,不满足匹配。

q  “2345”和“34”比较,不满足匹配。

q  “345”和“34”比较,满足匹配。

面试例题13:编程实现字符串中各单词的翻转。

考点:字符串相关的综合编程能力。

出现频率:★★★

编写函数,将“I am from Shanghai”倒置为“Shanghai from am I”,即将句子中的单词位置倒置,而不改变单词内部的结构。

解析

第1种方法代码如下:

1    #include <iostream>

2    using namespace std;

3

4    void RevStr(char *src)

5    {

6        char *start = src, *end = src, *ptr = src;

7                                           

8        while(*ptr++ != '\0')                //遍历字符串

9        {

10           if(*ptr == ' ' || *ptr == '\0')      //找到一个单词

11           {

12               end = ptr - 1;           //end指向单词末尾

13               while(start < end)

14               swap(*start++, *end--);  //把单词的字母逆置

15   

16               start = end = ptr+1;      //指向下一个单词开头

17           }

18       }

19       start = src, end = ptr-2;            //start指向字符串开头,end指向字符串末尾

20       while(start < end)

21       {

22           swap(*start++, *end--);       //把整个字符串逆置

23       }

24   }

25    

26   int main()

27   {

28       char src[] = "I am from Shanghai";

29       cout << src << "\n";

30       RevStr(src);

31       cout << src << "\n";

32   

33       return 0;

34   }

程序输出结果:

1    I am from Shanghai

2    Shanghai From am I

RevStr函数有两个转换步骤:代码第8~18行将src中所有的单词进行翻转,其结果是src的内容变为“I ma morf iahgnahS”,然后代码第20~23行再进行全局翻转。

第2种方法代码如下:

1    #include <iostream>

2    using namespace std;

3

4    void RevStr(char *src)

5    {

6        char *start = src, *end = src, *ptr = src;

7    

8        while(*ptr++ != '\0'); 

9        end = ptr-2;                       //找到字符串末尾

10       while(start < end)

11       {

12           swap(*start++, *end--);         //逆置整个字符串

13       }

14       

15       start = src, end = ptr-2;

16       ptr = start;

17       while(*ptr++ != '\0')

18       {

19           if(*ptr == ' ' || *ptr == '\0')       //找到单词

20           {

21               end = ptr - 1;             //end指向单词末尾

22               while(start < end)

23               swap(*start++, *end--);    //逆置单词

24   

25               start = end = ptr+1;       //指向下一个单词开头

26           }

27       }

28   }

29   

30   int main()

31   {

32       char src[] = "I am from Shanghai";

33       cout << src << "\n";

34       RevStr(src);

35       cout << src << "\n";

36   

37       return 0;

38   }

程序输出结果:

    I am from Shan ghai

    Shanghai from am I

RevStr函数转换步骤与第1种方法相反,即代码第10~11行将src进行全局翻转, src的内容变为“iahgnahS morf ma I”,然后代码第17~第27行再把所有的单词进行翻转。

从上面的代码分析可以看出,两种方法都是采用了两个步骤,即字符串全局翻转和各个单词局部翻转,只是步骤的顺序不同,但是得到的结果都是一致的。

 

面试例题14:编程判断字符串是否为回文。

考点:字符串相关的综合编程能力。

出现频率:★★★★

判断一个字符串是不是回文。

解析

根据题目要求,我们可以从一个字符串的两端进行遍历比较。例如对于“level”字符串,我们可以进行如下操作。

q  计算需要比较的次数。由于“level”字符串长度为5,是奇数,因此比较2次。

q  第1次比较:看“level”的第1个字符与最后1个字符是否相等,如果相等进行第2次比较。

q  第2次比较:看“level”的第2个字符与倒数第2个字符是否相等,如果相等则是回文。

只要在上面的比较过程中有一个不相等,则字符串不是回文。根据以上思路,程序代码如下所示:

1    #include <iostream>

2    using namespace std;

3    

4    int IsRevStr(char *str)

5    {

6        int i, len;

7        int found = 1;                     //1表示是回文字符串,0表示不是

8    

9        if(str == NULL)                   //判断str的有效性

10       {

11           return -1;

12       }

13       len = strlen(str);                   //获得字符串长度

14       for(i=0; i<len/2; i++)

15       {

16           if(*(str+i) != *(str+len-i-1))      //遍历中如果发现相应头尾字符不等

17           {                            //则字符串不是回文

18               found=0;

19               break;

20           }

21       }

22       return found;

23   }

24

25   int main()

26   {

27       char str1[10] = "1234321";         //回文字符串

28       char str2[10] = "1234221";         //非回文字符串

29       

30       int test1 = IsRevStr(str1);          //测试str1是不是回文

31       int test2 = IsRevStr(str2);          //测试str2是不是回文

32   

33       cout << "str1 is " << (test1 == 1 ? "": "not ") 

34                           << "reverse string." << endl;

35       cout << "str2 is " << (test2 == 1 ? "": "not ") 

36                           << "reverse string." << endl;

37   

38       return 0;

39   }

这个程序中的IsRevStr()函数用于判断字符串是否是回文字符串,如果是则返回1,否则返回0。输出结果:

    str1 is reverse string.

    str2 is not reverse string.

 

面试例题15:编程实现stcmp库函数。

考点:库函数strcmp的实现细节。

出现频率:★★★★★

解析

此题实际上就是实现C/C++库函数中的strcmp函数。对于两个字符串str1和str2,若相等则返回0,若str1大于str2则返回1,若str1小于str2返回-1。

程序代码如下所示:

1    #include <iostream>

2    using namespace std;

3

4    int mystrcmp(const char *src, const char *dst)

5    {

6        int ret = 0 ;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -