2022.9.7实训笔记

193 阅读1分钟

数组

数组名是其第一个元素的地址。指针可以指向数组,也可以指向数组元素。 数组后面的元素,可读不可写,见下面的例子

数组名是一个表示地址的常量,数组一旦声明,地址就确定,不能做++,--操作。 他们有时可以互换使用,但使用指针比使用数组下标快两倍。

二维数组,数组名a,a指向其0行第一个元素,&a为上一层地址,*a为下一层地址,a+1为1行地址

a的值和&a[0]是一样的,同一个地址

a[1] + 1        //a表示第一行的地址,a[0]表示第一行的数组名,所以a[0]也表示这行第一个元素的地址
&a[1][1]
(*(a + 1)) +1   //a+1表示第二行的地址,假设第二行数组名为b,则&b就是a+1,则*(a+1)就是b,表示第二行第一个元素的地址
a + 5


  	int a[3][3];
	
	cout<<&a[0]<<endl; //0x7ffe83f95150   
	cout<<&a[1]<<endl; //0x7ffe83f9515c   +12
	
	
	
	cout<<&a<<endl;    /0x7ffe83f95150   
	cout<<&a+1<<endl;  //0x7ffe83f95174   
	cout<<&a+2<<endl;  //0x7ffe83f95198

000476.png

数组传参给函数后自动退化成地址

此时数据名和指针是等价的。 不能通过sizeof得到数组的长度。因为此时数组参数相当于第一个元素的指针。 解决办法是把长度一起传过来,或者是使用一种规则,指定特定字符表示结束,如字符串中的'\0',如

void printArray(char *str) { 
    while(*str){ 
        puts(*str++);
}
}



数组名不可重新赋值 数组在分配空间后,地址就确定下来,此时数组名表示首地址,不可再变。

void f(char a[])
{
    ++a; 
}
//上面代码好像可以修改数组名的值,实际上,函数的数组参数并不是真正的数组,而是实实在在的指针。它和下面代码等价
void f(char *a)
{
    ++a; 
}
//如果你不希望数组名被改变,可以改写成下面代码,但必须使用指针语法
void f(char *const a)
{
    ++a; //非法
}

array_name 和 &array_name的区别: 前者是指向数组中第一个元素的地址。 后者是指向整个数组的地址

字符数组和字符串 在定义一个字符串变量时,你需要有一个足以容纳该字符串的数组或指针,并且要保证为终止符NUL留出空间。下面的代码就有问题

char greeting[12]; 
strcpy(greeting, "Hello, world");
/* 上例中,greeting只能容纳12个字符,而"Hello, world"有13个字符(包括NUL),因此NUL字符会被复制到greeting以外的某个位置,这可能会毁掉greeting四周内存空间中的一些数据。 */

char greeting[12] = "Hello, world"; 
//greeting是一个字符数组,而不是一个字符串。因为上例没有为终卡符NUL留出空间,所以greeting不包含NUL。


char greeting[] = "Hello, world";
//此时编译器会计算出需要多大的空间来容纳所有内容,包括NUL字符。

strcmp strlen源码分析

int __cdecl strcmp (const char *src, const char *dst)
{
    int ret = 0 ;
    while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
    {
        ++src;
        ++dst;
    }
    if ( ret < 0 )
        ret = -1 ;
    else if ( ret > 0 )
        ret = 1 ;
    return( ret );
}



size_t strlen_a(const char * str) {
2     size_t length = 0 ;
3     while (*str++ )
4         ++ length;
5     return  length;
6 }