Интересно, что ни один из ответов на этой странице не упоминает два крайних случая, надеюсь, никто не возражает, если я их добавлю:
Родовые словари в .NET не являются потокобезопасными, а иногда могут бросать NullReference
или даже (чаще) a KeyNotFoundException
при попытке получить доступ к ключу из двух параллельных потоков. Исключение в этом случае является довольно ошибочным.
Если код NullReferenceException
задан кодом unsafe
, вы можете посмотреть на переменные указателя , и проверьте их на IntPtr.Zero
или что-то в этом роде. Это одно и то же («исключение нулевого указателя»), но в небезопасном коде переменные часто переводятся в типы значений / массивы и т. Д., И вы ударяете головой о стену, задаваясь вопросом, как тип значения может исключение.
(Еще одна причина для небезопасного использования небезопасного кода, если вам это нужно)
В C99 вы можете предоставить размеры массива перед его передачей:
void array_function(int m, int n, float a[m][n])
{
for (int i = 0; i < m; i++)
for (int j = 0; j < n; j++)
a[i][j] = 0.0;
}
void another_function(void)
{
float a1[10][20];
float a2[15][15];
array_function(10, 20, a1);
array_function(15, 15, a2);
}
Хакерным способом было бы передать первый элемент и выполнить вычисления массива вручную.
Этот длинный пример использует макрос, чтобы полуавтоматически извлекать размеры массива для использования в вызове.
struct font { int disp, trig; };
struct font font3[3][3];
#define dim(x) (sizeof(x)/sizeof*(x))
#define font_and_dims(x) (struct font *)x, dim(x), dim(*x)
int print(char *s, struct font *font, int dimy, int dimx) { ... }
main(){ ... print(*av, font_and_dims(font3)); ... }
Вызванная функция обращается к массиву с трудом.
print(){ ... font[row*dimx+col] ... }
Не бойтесь прокручивать вниз: хороший материал внизу! Эта уродливая, педантичная функция в верхней части обеспечивает максимальную мобильность штриховки; но он является язвой, я допускаю.
#include <stdio.h>
#include <string.h>
int ao(int c) {
switch(c) {
case '0':return 0;
case '1':return 1;
case '2':return 2;
case '3':return 3;
case '4':return 4;
case '5':return 5;
case '6':return 6;
case '7':return 7;
case '8':return 8;
case '9':return 9;
case 'A':case 'a':return 10;
case 'B':case 'b':return 11;
case 'C':case 'c':return 12;
case 'D':case 'd':return 13;
case 'E':case 'e':return 14;
case 'F':case 'f':return 15;
default:return -1;
}
}
enum {
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
D = 1 << 3,
E = 1 << 4,
F = 1 << 5,
G = 1 << 6,
H = 1 << 7 };
int seg[] = {
/*0*/ A|B|C|D|E|F,
/*1*/ B|C,
/*2*/ A|B| D|E| G,
/*3*/ A|B|C|D| G,
/*4*/ B|C| F|G,
/*5*/ A| C|D| F|G,
/*6*/ A| C|D|E|F|G,
/*7*/ A|B|C,
/*8*/ A|B|C|D|E|F|G,
/*9*/ A|B|C| F|G,
/*A*/ A|B|C|D|E| G, /*A|B|C| E|F|G,*/
/*b*/ C|D|E|F|G,
/*C*/ D|E| G, /*A| D|E|F,*/
/*d*/ B|C|D|E| G,
/*E*/ A|B| D|E|F|G, /*A| D|E|F|G,*/
/*F*/ A| E|F|G,
};
struct font {
int disp, trig;
};
/* _
|_|
|_|
*/
struct font font3[3][3] = {
{ { 0,0}, {'_',A}, { 0,0} },
{ {'|',F}, {'_',G}, {'|',B} },
{ {'|',E}, {'_',D}, {'|',C} },
};
/* ___
| |
|___|
| |
|___|
*/
struct font font5[5][5] = {
{ { 0,0}, {'_',A}, {'_',A}, {'_',A}, { 0,0} },
{ {'|',F}, { 0,0}, { 0,0}, { 0,0}, {'|',B} },
{ {'|',F}, {'_',G}, {'_',G}, {'_',G}, {'|',B} },
{ {'|',E}, { 0,0}, { 0,0}, { 0,0}, {'|',C} },
{ {'|',E}, {'_',D}, {'_',D}, {'_',D}, {'|',C} }
};
/* ____
| |
| |
| |
|____|
| |
| |
| |
|____|
*/
struct font font9[9][7] = {
{ { 0,0}, {'_',A}, {'_',A}, {'_',A}, {'_',A}, { 0,0}, {0,0} },
{ {'|',F}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',B}, {0,0} },
{ {'|',F}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',B}, {0,0} },
{ {'|',F}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',B}, {0,0} },
{ {'|',F}, {'_',G}, {'_',G}, {'_',G}, {'_',G}, {'|',B}, {0,0} },
{ {'|',E}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',C}, {0,0} },
{ {'|',E}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',C}, {0,0} },
{ {'|',E}, { 0,0}, { 0,0}, { 0,0}, { 0,0}, {'|',C}, {0,0} },
{ {'|',E}, {'_',D}, {'_',D}, {'_',D}, {'_',D}, {'|',C}, {0,0} },
};
#define dim(x) (sizeof(x)/sizeof*(x))
#define font_and_dims(x) (struct font *)x, dim(x), dim(*x)
int print(char *s, struct font *font, int dimy, int dimx) {
int row, col;
char *sp;
for (row = 0; row < dimy; row++) {
for (sp = s; *sp; sp++) {
for (col = 0; col < dimx; col++) {
putchar( seg[ao(*sp)] & font[row*dimx+col].trig ?
font[row*dimx+col].disp : ' ');
}
}
putchar('\n');
}
}
int main(int ac, char **av) {
enum { F1, F2, F3 } fz = F1;
for (++av,--ac;ac;ac--,av++) {
if (av[0][0] == '-') {
switch (av[0][1]) {
case '1': fz=F1; continue;
case '2': fz=F2; continue;
case '3': fz=F3; continue;
default: fprintf(stderr, "Unrecognized Option!\n");
}
}
if (strspn(*av, "0123456789abcdefABCDEF") != strlen(*av))
fprintf(stderr, "Hex only!\n");
else
switch(fz) {
case F1: print(*av, font_and_dims(font3)); break;
case F2: print(*av, font_and_dims(font5)); break;
case F3: print(*av, font_and_dims(font9)); break;
default: fprintf(stderr, "Invalid Font!\n");
}
}
return 0;
}
Попробуйте что-то вроде этого:
int MyFunction(size_t ncols, const float arr[][ncols])
{
// ...
}
, когда мы передаем 2D-массив в качестве аргументов для функций, которые необязательно указывать в большинстве измерений. Главное здесь - когда любые изменения, внесенные в функции, которые изменяются, отражают функции вызова, потому что когда мы передаем двухмерный массив в качестве аргументов означает, что на самом деле функции принимают указатель на 1-D массив. И размер этого числа столбцов. Примеры
1 - int funct(int (*a) [4]);
здесь a является указателем на массив целых чисел. мы можем просто передать это так же
2- void funct(int a[][4]);
, как я сказал ранее, оставив большую часть, всегда является необязательным. В первом примере размер a будет 4, потому что это обычно просто указатель. в то время как размер * a будет 16, потому что у нас есть 4 столбца, и для каждого столбца мы имеем 4 байта, поэтому 4 * 4 = 16 байтов.
Но наиболее предпочтительным способом всегда является распределение динамической памяти.
Надеюсь, у тебя ясно
В C89 u можно использовать
typedef float OneRow[2];
void func(OneRow *arr)
{
printf("%f",arr[1][0]);
}
...
OneRow arr[] = {{1,2},{3,4},{5,6}};
func(arr);
...