天天看点

数组(array)应用Array of Strings in C++Array Decay in C++How to find size of array in C/C++ without using sizeof ?

Array of Strings in C++

在C++中有3中方法可以创建Array of Strings

  1. 使用二维数组(C/C++)

1.1 用字符数组表示的字符串

字符数组的初始化有两种

char str2[6]="china";
    char str3[5] = {'c','h','i','n','a'};
           

第一种初始化方式必须要为'\0'分配空间,也就是说, 用一个字符串初始化字符数组时,字符数组除了要保存这个字符串以外,还必须要保存至少一个'\0',

第二个初始化方式是用每一个单独的字符去初始化字符数组,在这种情况下不需要保存'\0', 只要满足字符数组的空间>=所要分配的字符大小即可。

注意:字符数组的赋值不能用一个字符串赋值,而只能使用单个字符去对数组元素一一赋值。

在C语言中还可以用字符指针指向字符串:

char *str1="china";
           

str指向的是大小为5字节的内存空间,在这个空间中没有'\0',这个空间的首地址保存在str1中。

不同于字符数组,对字符指针可以使用字符串整体赋值:

str1 = ”I love China";
           
char color[][10] = {"blue","Red","orange","yellow"};
           
1.2 用二维数组表示多个字符串
char color[][10] = {"blue","Red","orange","yellow"};//sizeof(color) = 40
            
for(int i = 0; i < 4;i++)
    cout<<color[i]<<endl;
           
//由于C/C++的多维数组是行优先,所以color数组的元素分布如下:
           
b l u e \0 \0 \0 \0 \0 \0
R e d \0 \0 \0 \0 \0 \0 \0
o r a n g e \0 \0 \0 \0
y e l l o w \0 \0 \0 \0

color[i]就是第i行的字符串的首地址。

输出是

数组(array)应用Array of Strings in C++Array Decay in C++How to find size of array in C/C++ without using sizeof ?
这种方法的缺点:
  • Number of Strings and Size of String – both the values are fixed.
  • A 2D array is allocated, whose second dimension is equal to maximum sized string which causes wastage of space.
  1. 使用string(C++)
#include<bits/stdc++.h>
using namespace std;
 
int main()
{
    // Initialize String Array
    string colour[4] = {"Blue", "Red", "Orange", "Yellow"};
     
    // Print Strings
    for (int i = 0; i < 4; i++) 
        cout << colour[i] << "\n";
}
           

这种方法的缺点:

Array is of fixed Size

  1. 使用vectors(C++) STL Container Vector can be used to dynamically allocate Array.
    // C++ program to demonstrate vector of strings using
    #include<bits/stdc++.h>
    using namespace std;
     
    int main()
    {
        // Declaring Vector of String type
        vector <string> colour;
     
        // Initialize vector with strings using push_back 
        // command
        colour.push_back("Blue");
        colour.push_back("Red");
        colour.push_back("Orange");
        colour.push_back("Yellow");
     
        // Print Strings stored in Vector
        for (int i=0; i<colour.size(); i++)    
            cout << colour[i] << "\n";    
    }
               
    从以上3点来看,vector应该是c++中创建字符串数组最好的方法了

注意:‘\0'在C语言中是 字符串结束符,所以只有数组在处理字符串时才会用多余的一个字节来保存它,在其他情况(非字符数组)下,数组不会保存它

Array Decay in C++

What is Array Decay?

数组退化是指数组丢失了数组元素的类型和数组的大小。这通常发生在向函数按值传递或传递指针参数时,结果就是仅仅把实参的首地址传给了形参的数组,这时数组就退化为一个指针,数组的大小也会变成指针的大小而不是原数组的大小。

举个简单的例子:

#include <iostream>
using namespace std;
 
void findSize(int arr[])
{
    cout << sizeof(arr) << endl;
}
 
int main()
{
    int a[10];
    cout << sizeof(a) << " ";
    findSize(a);
    return 0;
}
           
输出
40 8      
d
// C++ code to demonstrate array decay
#include<iostream>
using namespace std;
 
// Driver function to show Array decay
// Passing array by value
void aDecay(int *p)
{
    // Printing size of pointer
    cout << "Modified size of array is by "
            " passing by value: ";
    cout << sizeof(p) << endl;
}
 
// Function to show that array decay happens 
// even if we use pointer
void pDecay(int (*p)[7])
{
    // Printing size of array
    cout << "Modified size of array by "
            "passing by pointer: ";
    cout << sizeof(p) << endl;
}
 
int main()
{
    int a[7] = {1, 2, 3, 4, 5, 6, 7,};
 
    // Printing original size of array
    cout << "Actual size of array is: ";
    cout << sizeof(a) <<endl;
 
    // Calling function by value
    aDecay(a);
     
    // Calling function by pointer
    pDecay(&a);   
 
    return 0;
}
           
输出
Actual size of array is: 28
Modified size of array by passing by value: 8
Modified size of array by passing by pointer: 8      

How to prevent Array Decay?

一个典型的解决办法就是把数组大小也作为一个参数传给函数,并且对数组参数不要用sizeof。

另外一个解决办法就是把数组按引用传递给函数,这样就避免了数组转化为指针,也就避免了退化。比如

// C++ code to demonstrate prevention of
// decay of array
#include<iostream>
using namespace std;
 
// A function that prevents Array decay
// by passing array by reference
void fun(int (&p)[7])
{
    // Printing size of array
    cout << "Modified size of array by "
            "passing by reference: ";
    cout << sizeof(p) << endl;
}
 
int main()
{
    int a[7] = {1, 2, 3, 4, 5, 6, 7,};
 
    // Printing original size of array
    cout << "Actual size of array is: ";
    cout << sizeof(a) <<endl;
 
    // Calling function by reference
    fun(a);
 
    return 0;
}
           
其它知识点:
  • 数组指针:int (*t)[N] 表示一个数组指针,它的意思是,t是一个指向 在内存中连续存储的 N个int数据所组成的 块的指针,N必须与实参二维数组的列值相同。先看小括号得知t是一个指针,往右看得知它指向的是数组,再看最左边,数组元素是int型的。(所有的指针都可以这么解读,包括函数指针)
  • 指针数组 :int (*t)[N] 表示t是一个数组,其中的元素是int*类型。
  • 数组引用:int (&t)[N] 表示t是一个数组的引用,其它的意义同数组指针,可以作为其它数组的呃别名。

How to find size of array in C/C++ without using sizeof ?

举例:

// C++ program to find size of an array by using a 
// pointer hack.
#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    int  arr[] = {1, 2, 3, 4, 5, 6};
    int size = *(&arr + 1) - arr;
    cout << "Number of elements in arr[] is "
         << size;
    return 0;
}
           

在解释原理之前,先说明 arr与&arr的区别

如果分别打印arr和&arr的值,你会发现这两者的值是一样的:

printf("array=%p : &array=%p\n", array, &array);  
   printf("array+1 = %p : &array + 1 = %p", array+1, &array+1);
           

然而将它们分别加1以后的值就不一样了,这是因为 arr与&arr虽然都指向相同的地址,但是地址的类型是不同的。

  • arr指向的是数组内的第一个元素的首地址,该元素类型是int,所以arr+1相当于第一个元素的首地址加4
  • &arr指向的是整个数组的首地址,类型是数组,所以&arr+1就相当于数组的首地址加数组的大小(单位是byte,本例是24=0x18)

原理:

&arr ==> Pointer to an array of 6 elements.
         [See this for difference between &arr
          and arr]   

(&arr + 1) ==> Address of 6 integers ahead as
               pointer type is pointer to array
               of 6 integers.

*(&arr + 1) ==> Same address as (&arr + 1), but 
                type of pointer is "int *".类型转化

*(&arr + 1) - arr ==> Since *(&arr + 1) points 
                   to the address 6 integers
                   ahead of arr, the difference
                   between two is 6. 利用指针减法