c语言字符串详细

1.字符串字面量。

"Candy \nIs dandy \nBut liquor \nIs quicker."

在c++中叫字符串字面值.可以在字符串内embed转移序列,例如'\n'

谨慎在字符串中embed八进制和hex转移序列,八进制转移序列以/开始,十六进制转移序列以/x(x必须小写)开始,八进制转移序列在三个数字(必须0~7范围内)之后结束或者以第一个非八进制以内的数字结束(数字大于等于8就结束)。

十六进制/x后面没有限制,以第一个非十六进制数字(大于f)结束。注意十六进制的数字大小写均可(从编译器运行结果得到)。例如看下面代码:

#include <stdio.h>
int main()
{
if(('\xAA') ==  ('\xaa'))
        printf("equal");
else 
        printf("not equal.");
    return 0;
}

运行结果是:

equal

2.延续字符串字面值。

(1)方法1:采用 \

例如   "i am a student   \

   and you are a teacher. "

特点:第一行以\(不包含)处结束,第二行以行首开始。

(2)方法2:当两条或者多条字符串相邻时候,c语言会自动合并字符串。利用这个规律可以这样书写

"i am a student  "

" and you are a teacher. "

最后编译器会自己把字符串合并成。"i am a student   and you are a teacher. "

3.字符串字面量的存储。c语言把字符串字面量当成字符数组来存储的。当c语言遇到长度为n的字符串,那么它会为字符串字面量分配长度n+1的内存空间,末尾加'\0'。注意:这里不要混淆'\0'、'0'、'  ',空字符的码值为0,而'0'的码值(ASCII)为48,空格'  ' ASCll码值是32。切记,如果字符数组默认初始化,那么就是' \0'.

字符数组默认初始化时候,每个字符也是赋值'\0'而不是空格键,算术类型数组初始化每个数字都是0.

空字符串是"",空字符串作为单独的一个空字符存储,'\0'

字符串字面之是当成数组来存储的,所以字符串字面之会被当成是指针(数组名字会被当成指针).例如,printf("abcde");那么会传递给printf函数字符串"abcde"的地址(即指向字符a的内存单元的指针).

4.字符串字面值会被当成是指针。

例如 "abc"

printf("abc");这里“abc”会被当成是指针,指向字母a的内存单元。

printf 和scanf 都接受char *类型作为他的第一个参数。

5.字符串字面值的操作。

(1)字符串字面值不能更改。看下面的代码:

#include <stdio.h>
int main()
{
char *str = "abcde";
*str = 'a';
printf("%s",str);
   return 0;
}                                                                         
                

运行结果发生运行时错误:

r@r:~/coml_/c/13/2$ gcc 3.c -o 123
r@r:~/coml_/c/13/2$ ./123
Segmentation fault (core dumped)
r@r:~/coml_/c/13/2$ 

结论:不能更改字符串字面值的内容。但是可以使char *对象指向别的字符串,例如,

#include <stdio.h>
int main()
{
char *str = "abcde";
printf("%s\n",str);
//str 重新指向另一个字符串字面量
str = "efghikasdfasd fasdf asdf asdf asf";
printf("%s",str);
return 0;

运行结果如下:

abcde
efghikasdfasd fasdf asdf asdf asfr

意外的地方:还能超过原来字符串的长度。

(2)一半情况下,可以在需要char *的任何地方使用字符串字面值。

例如,char *p;

p = "abc";这个操作不是拷贝字符串,是把字符a的地址赋值给p,也就是说指针变量p的赋值过程,而不是字符串整体的赋值过程。

(3)指针有下标操作,字符串字面值也有

"abc"[1],指的是字符b

如下函数,把整数转换成十六进制字符的形式。

char number_to_hex(int n)
{
return "0123456789ABCDEF"
}                                                                         
  

(4)这里注意十六进制和八进制转移序列是不一样的

          (a)十六进制数的定义\x00(x大写小写都可以,数字部分没有长度要求),八进制数的定义,\012(数字0开头就是八进制数,\0后面的数字也没有长度限制

         (b)十六进制转义序列必须\x开头(x必须小写,而且后面数字部分最多2位从0~ff),八进制转移序列\开头,后面数字最多3位,看下面的图也能复习下

6.字符串字面值和字符常量不能互换,看下面的代码:

#include <stdio.h>
int main()
{
printf("\n");
printf('\n');  //这里引发错误
    return 0;
}        

gcc编译器编译结果如下:

r@r:~/coml_/c/13/2$ gcc 4.c -o 123
4.c: In function ‘main’:
4.c:5:8: warning: passing argument 1 of ‘printf’ makes pointer from integer without a cast [-Wint-conversion]
    5 | printf('\n');
      |        ^~~~
      |        |
      |        int
In file included from 4.c:1:
/usr/include/stdio.h:332:43: note: expected ‘const char * restrict’ but argument is of type ‘int’
  332 | extern int printf (const char *__restrict __format, ...);
      |                    ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~
4.c:5:1: warning: format not a string literal and no format arguments [-Wformat-security]
    5 | printf('\n');

7.字符串变量。注意必须以“\0”结尾,否则库函数调用它会出现未定义的行为。

#include <stdio.h>
#define STR_LEN 20
int main()
{
//方法1:直接定义成字符数组+初始化
char str[STR_LEN + 1] = "you are welcome.";
//方法2:直接定义为char * + 初始化
char * str1 = "you are welcome.";
//方法3:先定义一个字符数组,和一个char *,把char *对象指向一个char 数组
char str2[STR_LEN + 1],*str3;
str3 = str2;
//方法4:先定义一个char *,后来可以指向一个字符串字面值
char *ptr;
ptr = "you are welcome";
puts(ptr);
  return 0;
}

但是如果要使用scanf读入char*,则必须先开辟足够空间,也就是,必须先声明为 char [STR_LEN + 1]类型,而不能申明为char *类型。

char *p;  //仅仅给指针p开辟了足够存放一个指针的空间.而不能给字符串分配空间。如果利用p读入,会引发错误:

#include <stdio.h>
int main()
{
char *p;
scanf("%s",p);
printf("%s",p);
  return 0;
}

运行结果如下:按照要求输入了  you aresdf后,输出确是null

you arasdf
(null)

8.初始化字符串变量

c语言处理数组初始化式的时候,当数组初始化式被数组本身短的时候,余下的数组元素会被初始化为0(元素是int,float,double的情况),char 数组遵守同样的规则,会以'\0'补充。

不论给char *,或者给char []类型赋值(值类型是字符串字面量),那么都会自动在结束时候以'\0'补充

#include <stdio.h>
int main()
{
double d[12] = {0.0};
int i;
for(i = 0; i!= 12; ++i)
{
printf("%f\n",d[i]);
}
   return 0;
}
~   

运行结果如下:

0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000

9.字符数组和字符指针

相同点:任何接受字符数组或者字符指针的地方,这两个都可以作实际参数。

不同点:

(1)字符数组可以修改某个字符的值,而字符指针不能修改字符串字面值。

(2)字符数组的名字是数组名,而字符指针是变量,可以在执行的时候指向其他字符串。

例如,char *p,这里p是一个指针变量,指向char对象。p的值是可以改变的,仅仅如此(p指向的对象的不能改变,区分*p = ...(不合法), 和p = ...(合法))

char *p;

p = "abcde";//合法,这里更改的是p的值。p是一个变量,当然可以更改了。

*p = "efghi";//不合法,这里要改变p指向的那个字符串字面量,会报错。

10.字符串的读写

(1)读

利用scanf或者fget();

特点:会忽略开始的后面的一切空白,例如输入   a   bc def,那么会忽略开始的空格,最后把a读入,后面的一些在内存中缓存,等待后续需要读入的时候。

(2)写

                 printf("")会严格一个一个地输出,直到遇到第一个'\0'为止,如果字符串末尾没有'\0',会继续写出,直到遇到内存中的第一个'\0'为止。

                puts(),会在行末直接加一个'\n'(自动换行)

(3)自己编写读取字符串函数要解决的问题如下

   (a)什么时候开始读取(是否忽略开始的空白字符)(b)怎么结束’\n’,空格还是某个字符,结束字符是否要写入字符串  (c)如果读取的字符串太长,那么多余的字符直接忽,还是把它留给下一次的输入操作。

例如,不忽略换行符,在第一个换行符结束,且换行符不存在字符串中,则如下编写,代码中的函数read():

#include <stdio.h>
#define LEN 20
int read(char str[],int n);
void print(char str[],int n);
int main()
{
char array[LEN + 1] = {' '};
read(array,LEN);
print(array,LEN+1);
    return 0;
}
int read(char str[],int n)
{
char ch;
char *p = str;
int i = 0;
while((ch = getchar()) != '\n')
{
 if(i < n)
 { *p ++ = ch;
     i++;
  }
}
*p = '\0';
return i;

}
void print(char str[],int n)
{
int i = 0;
for(i = 0; i!= n; ++i)
  {
    printf("%c",str[i]);
  }
}

                   函数read()也可以如下简单的编写:

int read(char str[],int n)
{int i = 0;
char ch;
  while((ch = getchar()) != '\n')
  {
  if(i < n)
      str[i ++] = ch;
  }
  str[i] = '\0';  //terminates string
  return i;       //number of characters stored
}

scanf函数和gets函数会在末尾自动加空字符,然而,自己编写函数要自己添加空字符。

猜你喜欢

转载自blog.csdn.net/digitalkee/article/details/112757288
今日推荐