这个问题的目的是提供一个关于如何在C中动态正确分配多维数组的参考.这是一个经常被误解的主题,即使在一些C编程书籍中也很难解释.因此,即使是经验丰富的C程序员也很难做到正确.
我从编程教师/书籍/教程中了解到,动态分配多维数组的正确方法是使用指针指针.
然而,SO上的几个高代表用户现在告诉我这是错误和不好的做法.他们说指针到指针不是数组,我实际上并没有分配数组,而且我的代码不必要地慢.
这就是我教我分配多维数组的方法:
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
int** arr_alloc (size_t x, size_t y)
{
int** pp = malloc(sizeof(*pp) * x);
assert(pp != NULL);
for(size_t i=0; i<x; i++)
{
pp[i] = malloc(sizeof(**pp) * y);
assert(pp[i] != NULL);
}
return pp;
}
int** arr_fill (int** pp, size_t x, size_t y)
{
for(size_t i=0; i<x; i++)
{
for(size_t j=0; j<y; j++)
{
pp[i][j] = (int)j + 1;
}
}
return pp;
}
void arr_print (int** pp, size_t x, size_t y) …Run Code Online (Sandbox Code Playgroud) c arrays dynamic-arrays dynamic-allocation variable-length-array
我的理解是数组只是指向一系列值的常量指针,当你在C中声明一个数组时,你就是声明一个指针并为它所指向的序列分配空间.
但这让我感到困惑:以下代码:
char y[20];
char *z = y;
printf("y size is %lu\n", sizeof(y));
printf("y is %p\n", y);
printf("z size is %lu\n", sizeof(z));
printf("z is %p\n", z);
Run Code Online (Sandbox Code Playgroud)
使用Apple GCC编译时会得到以下结果:
y size is 20
y is 0x7fff5fbff930
z size is 8
z is 0x7fff5fbff930
Run Code Online (Sandbox Code Playgroud)
(我的机器是64位,指针长8个字节).
如果'y'是常量指针,为什么它的大小为20,就像它指向的值序列一样?变量名'y'是否在编译时被内存地址替换为适当的?那么数组是C中的某种语法糖,它在编译时只是转换为指针的东西吗?
有人可以向我解释为什么以下代码的输出是说数组不相等?
int main()
{
int iar1[] = {1,2,3,4,5};
int iar2[] = {1,2,3,4,5};
if (iar1 == iar2)
cout << "Arrays are equal.";
else
cout << "Arrays are not equal.";
return 0;
}
Run Code Online (Sandbox Code Playgroud) 有人问我以下代码的输出是什么:
int a[5] = { 1, 3, 5, 7, 9 };
int *p = (int *)(&a + 1);
printf("%d, %d", *(a + 1), *(p - 1));
Run Code Online (Sandbox Code Playgroud)
3, 93, 12, 1答案是NO.1
很容易得到的*(a+1)是3。
但是 和int *p = (int *)(&a + 1);呢*(p - 1)?
char str[] = "beautiful earth";
memset(str, '*', 6);
printf("%s", str);
Output:
******ful earth
Run Code Online (Sandbox Code Playgroud)
1)像上面使用memset一样,我们可以只将几个整数数组索引值初始化为1,如下所示?
int arr[15];
memset(arr, 1, 6);
Run Code Online (Sandbox Code Playgroud) std::begin并std::end知道一个container或一个的开始和结束array.
它很容易知道end和begin的vector为例子,因为它是一个类,给出了这样的信息.但是,它如何知道如下结束array呢?
int simple_array[5]{1, 2, 3, 4, 5};
auto beg=std::begin(simple_array);
auto en=std::end(simple_array);
Run Code Online (Sandbox Code Playgroud)
std::begin并不难知道数组的起始位置.但它如何知道它的结束?将常数整数5存储在某处吗?
如果我得到一些低级信息的答案,我将不胜感激.
以下程序在gcc 4.8.2上两次打印相同的数字:
#include <stdio.h>
int main()
{
char a[13];
printf("sizeof a is %zu\n", sizeof a );
printf("sizeof(a) is %zu\n", sizeof(a));
}
Run Code Online (Sandbox Code Playgroud)
根据这篇reddit帖子,gcc在这方面并不符合标准,因为当数组到指针衰减没有发生时,括号表达式不在异常列表中.
这家伙是对的吗?这是相关的标准报价:
除非它是运算
sizeof符或一元运算&符的操作数,或者是用于初始化字符数组数组的字符串文字,或者是用于初始化与元素类型兼容的数组的宽字符串文字,否则具有wchar_t的左值类型'array of type'被转换为一个表达式,其类型为'指向类型的指针',指向数组对象的初始成员而不是左值.
为了清楚起见,他认为(a)应该触发数组到指针的衰减,因为上面的列表中没有括号括起来(sizeof运算符,一元运算&符,字符串文字作为初始值).
我正在读一本C++书,上面写着:
C++通过引用将数组传递给函数 - 被调用的函数可以修改调用者原始数组中的元素值.
它指的是这样的情况:
int hourlyTemperatures[ 24 ];
modifyArray( hourlyTemperatures, 24 );
Run Code Online (Sandbox Code Playgroud)
但是,这是香草C阵列指针在这里工作,对吧?没有使用C++"引用"技术,传递的是按值的指针,在这种情况下,是指向数组的第一个元素的指针.最终的结果是函数确实可以访问完整的原始数组,就像引用一样,但实际上并没有通过引用传递,对吧?
从这本Prentice Hall书中:

当使用C中的数组和指针时,人们会很快发现它们并不等同,尽管乍一看似乎是这样.我知道L值和R值的差异.不过,最近我试图找出一个可以与二维数组结合使用的指针类型,即
int foo[2][3];
int (*a)[3] = foo;
Run Code Online (Sandbox Code Playgroud)
不过,我只是不能找出编译器如何"理解"的类型定义,尽管常规运算符优先级规则*和[].相反,如果我使用typedef,问题会变得非常简单:
int foo[2][3];
typedef int my_t[3];
my_t *a = foo;
Run Code Online (Sandbox Code Playgroud)
在底线,有人可以回答我关于int (*a)[3]编译器如何读取该术语的问题吗?int a[3]很简单,int *a[3]也很简单.但那么,为什么不int *(a[3])呢?
编辑:当然,而不是"类型转换"我的意思是"typedef"(它只是一个错字).
我想知道为什么第一个语句有效,为什么不用c ++中的第二个语句
char a[10]="iqbal"; // it works
a="iqbal"; // does not work
Run Code Online (Sandbox Code Playgroud)