I want to define a data structure at compile time using macros. The data structure looks something like:
struct {
int a;
int b;
int c;
unsigned int top;
unsigned int first;
} array[N];
Where N is some compile time constant. User then defines a macro like so:
#define List \
(10, -3, 8, \
(-1, -1, 13, \
(0, -7, 15, Empty)), \
(-4, 14, 13, Empty)), \
(17, 0, 1, Empty), \
(3, 3, 3, \
(1, 1, 0, Empty)) \
from which the array shall be generated. The result would be:
array = {
[0] = {10, -3, 8, NoValue, 1/*array[1]*/},
[1] = {-1, -1, 13, 0/*array[0]*/, 2/*array[2]*/},
[2] = {0, 7, 15, 0/*array[0]*/, NoValue},
[3] = {-4, 14, 13, 0/*array[0]*/, NoValue},
[4] = {17, 0, 1, NoValue, NoValue},
[5] = {3, 3, 3, NoValue, 6/*array[6]*/},
[6] = {1, 1, 0, 5/*array[5]*/, NoValue},
};
Where #define NoValue 9000 /* special value used only for this purpose */. Basically create entry in array for every element enclosed in (). Additionally link sub-elements to the parent-element and the parent-element to its first sub-element.
What I have so far is using FOR_EACH macro from https://stackoverflow.com/a/11994395/1806687. The problem is that the macro that would define an array entry also contains FOR_EACH macro to iterate over any possible sub-elements which breaks down and doesn't work.
How can I make this work?
EDIT:
I guess the first obstacle is recursively iterating through the tree to define an enumeral for every element (). We could add a one more argument to every element like so #define List (Name1, 10, -3, 8, ... from which we can generate an enumeration whose values we can then use in place of array indices (top and first members).
#define List \
(Name1, 10, -3, 8, \
(Name2, -1, -1, 13, \
(Name3, 0, -7, 15, Empty)), \
(Name4, -4, 14, 13, Empty)), \
(Name5, 17, 0, 1, Empty), \
(Name6, 3, 3, 3, \
(Name7, 1, 1, 0, Empty)) \
#define EnumFromList(name, a, b, c, top, first) \
enum_##name,
enum NameEnum {
FOR_EACH(EnumFromList, List)
};
Still, nesting of the sub-elements prevents an easy solution (as far as I can see) to this.
EDIT2:
The actual data structure I am using looks more like:
struct {
int a;
int b;
int c;
unsigned int top;
unsigned int parent;
unsigned int first;
} array[N];
Where top is array index of top-parent-element parent is array index of direct(first)-parent-element and first is array index of first-sub-element.
Related
Write C code to initialize an array of 10 integers. If both sides of a number are smaller than it, then that number is the peak. Once you have all the peaks, create an array, store all the peaks in this new array and print them. The first question is I do not know how many peaks it may have, how to create the array to store peaks?
#include <stdio.h>
int main(void) {
int vals[10] = {1,2,3,1,4,6,3,8,9,1}; // initialize an array of 10 integers
int length = sizeof(vals) / sizeof(vals[0]);
int peaks;
for (int i = 1; i < length-1; i++) {
if (vals[i] > vals[i-1] && vals[i+1]) { // If both sides of a number are smaller than it
peaks[i] = vals[i];
}
printf("%d",peaks[i]);
return 0;
}
Just create an array the same size as the vals array. It's guaranteed that the number of peaks cannot be larger than the number of values. In reality the former will be much smaller than the latter as not every value can be a peak(1).
But, allowing for ten will be more than enough, without too much wastage.
Then you just use a variable to dictate how many peaks there are. For example, initialise the peak array as:
int peak[10];
size_t num_peaks = 0;
To add a peak to that array:
peak[num_peaks++] = new_peak;
And to process the peaks:
for (size_t peak_idx = 0; peak_idx < num_peaks; ++peak_idx)
do_something_with(peak[peak_idx]);
And, a couple of things to keep in mind:
Should you consider the first element to be a peak if the second is lower?
Ditto for the final element if the penultimate one is lower.
How do you handle plateaus (like 1, 3, 3, 2)? Neither of those 3 values are considered a peak under your current definition since the elements on either side are not both lower.
As a final suggestion, here is some Python code (you can convert it into C yourself, I tend to use Python as it's the ideal "pseudo-code" language) that will cater for what I believe is the best approach for finding peaks, by answering the questions above with:
Yes, first element can be a peak.
Yes, final element can also be a peak.
With plateaus, you effectively compress them into a single value and follow the normal rules, so 1, 3, 3, 2 is the same as 1, 3, 2.
The basic idea is to track the changes in direction (or gradient) so that you only consider it a peak when you switch from increasing to decreasing gradient. That can be achieved with the following code:
import random
def peaks(my_list):
# Edge case, no peaks for empty list.
if len(my_list) == 0: return []
# Peak accumulation list.
# Would be array for C as per my suggestions above.
my_peaks = []
# Start by assuming we're increasing to allow first element peak.
prev = my_list[0]
direction = "up"
# Process every item in list.
for item in my_list:
# If switching from rising to falling, that was a peak.
if item < prev and direction == "up":
my_peaks.append(prev)
direction = "down"
# If switching from falling to rising, that was a trough.
# Prepare to detect next peak.
elif item > prev and direction == "down":
direction = "up"
# Plateaus make no changes.
# Store previous to detect peak/trough.
prev = item
# If rising at end, it's considered a final peak.
if direction == "up":
my_peaks.append(prev)
return my_peaks
# This is a test harness to check results.
def find_peaks(my_list):
print(f"List: {my_list}")
print(f" -> {peaks(my_list)}\n")
find_peaks([])
find_peaks([1])
find_peaks([1, 2, 3])
find_peaks([3, 2, 1])
find_peaks([1, 2, 3, 3, 3, 3, 3, 2])
find_peaks([10, 9, 9, 9, 9, 8, 9])
find_peaks([1, 2, 1, 2, 1, 2, 1, 2, 1, 2])
for attempt in range(10):
count = 5 + random.randint(0, 10)
find_peaks([random.randint(5, 30) for _ in range(count)])
Hopefully, you'll see how this works from the comments and the following test output (I've inserted v characters to indicate the relevant peaks):
List: []
-> []
v
List: [1]
-> [1]
v
List: [1, 2, 3]
-> [3]
v
List: [3, 2, 1]
-> [3]
v
List: [1, 2, 3, 3, 3, 3, 3, 2]
-> [3]
vv v
List: [10, 9, 9, 9, 9, 8, 9]
-> [10, 9]
v v v v v
List: [1, 2, 1, 2, 1, 2, 1, 2, 1, 2]
-> [2, 2, 2, 2, 2]
vv vv vv vv
List: [30, 8, 7, 7, 29, 24, 15, 14, 7, 25, 17, 14, 27]
-> [30, 29, 25, 27]
vv vv vv vv
List: [10, 6, 16, 8, 18, 19, 25, 24, 18, 28]
-> [10, 16, 25, 28]
vv vv
List: [26, 13, 11, 13, 20, 17, 6, 6]
-> [26, 20]
vv vv vv vv vv
List: [17, 18, 30, 23, 14, 29, 17, 22, 22, 6, 15, 12, 11, 23]
-> [30, 29, 22, 15, 23]
vv vv vv
List: [26, 7, 16, 10, 23]
-> [26, 16, 23]
vv vv vv
List: [21, 12, 18, 14, 20]
-> [21, 18, 20]
vv vv vv
List: [27, 9, 13, 26, 15, 30]
-> [27, 26, 30]
vv vv vv
List: [11, 17, 21, 24, 26, 22, 16, 6, 7, 26, 16, 27]
-> [26, 26, 27]
vv vv vv vv
List: [12, 14, 9, 20, 21, 18, 6, 13, 10, 25, 5]
-> [14, 21, 13, 25]
vv vv
List: [17, 9, 30, 29, 7]
-> [17, 30]
This doesn't necessarily match your specific requirement that excludes the endpoints as possible peaks but that's fairly easy to adapt to by:
Starting the main loop with the second element rather than the first; and
Removing the final check for upward direction.
(1) The actual maximum number of peaks is about half the number of values, depending on how you define peak. With your current definition, the end points cannot be peaks since they have no values of the "other side" which can satisfy the "both sides of a number are smaller than it" requirement.
With the possibility that high values at the ends can be considered peaks, the maximum increases slightly.
With array sizes like ten, it's probably not worth worrying about the wastage of half the elements in the peaks array.
Once you have all the peaks, create an array...
Actually this implies a two-step approach. One pass to count the peaks, and a second to copy them into the new array.
At the same time it is misleading, because "having all the peaks" is not "determine the number of peaks".
Anyway, you can create an array at run-time with:
int *peaks = malloc(num_peaks * sizeof*peaks);
or simply as VLA:
int peaks[num_peaks];
(After obtaining num_peaks in a first run, in both cases)
On the other hand, this seems a bit complicated, since the first array has 10 integers by definition:
int length = sizeof(vals) / sizeof(vals[0]);
I would rather do this:
#define LENGTH = 10
int vals[LENGTH] = {1,2,3,1,4,
6,3,8,9,1};
Here vals is not a VLA, because LENGTH is turned into 10 at compile time.
You were so close. You set you loop limits correctly to allow you to check both sides of the current index in the vals[] array. By looping from 1 to length - 1 you can check the values at vals[i-1] and vals[i+1] each iteration. Neither end value can be a peak as there is no value on the opposite side to check.
However, after setting up your loop, you didn't check each side of vals[i] to determine if the current value was a peak. You need to do:
/* loop from 1 to length-1 checking value each side of current index */
for (int i = 1; i < length - 1; i++) {
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
...
Once you determine it is a peak, simply add vals[i] as the next element in the peaks[] array, e.g.
...
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
peaks[npeaks] = vals[i]; /* add value to peaks array */
npeaks += 1; /* increment no. of peaks */
}
}
A short example showing the complete program would be:
#include <stdio.h>
int main (void) {
int vals[] = {1,2,3,1,4,6,3,8,9,1},
length = sizeof vals / sizeof *vals,
peaks[sizeof vals] = {0}, /* create peaks array */
npeaks = 0; /* no. of peaks found */
/* loop from 1 to length-1 checking value each side of current index */
for (int i = 1; i < length - 1; i++) {
if (vals[i-1] < vals[i] && vals[i] > vals[i+1]) { /* if peak */
peaks[npeaks] = vals[i]; /* add value to peaks array */
npeaks += 1; /* increment no. of peaks */
}
}
puts ("peaks:"); /* output result */
for (int i = 0; i < npeaks; i++) {
printf (" peaks[%d] : %d\n", i, peaks[i]);
}
}
(note: when using sizeof with an expression, it is generally just sizeof expression, when using with a type (such as int), then it is generally sizeof(type), but note compilers will generally accept either sizeof(expression) or sizeof(type), but not sizeof type. See C11 Standard - 6.5.3 Unary operators)
Example Use/Output
$ ./bin/arrpeaks
peaks:
peaks[0] : 3
peaks[1] : 6
peaks[2] : 9
you can use this function to find the index of peak in an array and then you can print accordingly.
Using Binary Search.
int findPeakElement(int* nums, int numsSize) {
if(numsSize<=1) return 0;
int left=0;int right=numsSize-1;
int mid;
while(left!=right){
if(nums[left]>nums[left+1]) {
right=left;break;
}
else left+=1;
if(nums[right]>nums[right-1]){
left=right;break;
}
else right-=1;
mid=(right-left)/2+left;
if(nums[mid]<nums[mid+1])left=mid+1;
else right=mid;
}
return left;
}
I tried this code..As you can see the problem is the empty elements are zero. So, I tried to check with it but the thing is I can have 0 as an element.
int main()
{
int array[10] = {1, 2, 0, 3, 4};
printf("%d\n", sizeof(array)/ sizeof(*array)); // This is the size of array
int i = 0;
while(array[i] != 0 && i < 10) {
i++;
};
printf("%d\n", i);
return 0;
}```
You can't. int array[10] will always create an array of 10 elements and you can't ask the compiler which of them have been assigned.
What you could do is int array[] = {1, 2, 0, 3, 4} then the compiler will infer the number of elements for you and you'll have sizeof(array)/ sizeof(*array) == 5
First set the array to a number outside the range of your inputs. Like a negative number.
for(i = 0;i < 10;i++)
array[i] = -1;
or set it to INT_MAX or INT_MIN
int array[10] = {1 , 2, 0, 3} . How can I find out that there are 4 elements here?
How can you say there are 4 elements there as you declared that int array[10] with the size of 10 elements. This implies, you already know the no. of elements. Also, in this scenario, you can't use an if statement to determine the no. of elements as you probably know that in C, if you initialize an array of 10 elements with less than 10 values, rest of them will automatically be assigned to 0.
You have several options:
You know how many elements are in the initializer, so you create another variable that stores that number:int array[10] = {1, 2, 0, 3, 4};
int num_items = 5;
You'll need to update num_items as you "add" or "remove" items to the array. If you treat the array as a stack (only add or remove at the highest index), then this is easy-ish:array[num_items++] = 7; // adds 7 after 4
...
x = array[--num_items]; // x gets 7, 7 is "removed" from the array, need special
// case logic for element 0
You pick a value that isn't valid (say -1) and initialize the remaining elements explicitly:int array[10] = {1, 2, 0, 3, 4, -1, -1, -1, -1, -1 };
You size the array for the initializer, meaning it can only ever store that many elements:int array[] = {1, 2, 0, 3, 4};
Otherwise, you'll need to use a different data structure (such as a linked list) if you need a container that can grow or shrink as items are added or removed.
I built a simple function that, given two arrays aa[5] = {5, 4, 9, -1, 3} and bb[2] = {16, -11}, orders them in a third array cc[7].
#include<stdio.h>
void merge(int *, int *, int *, int, int);
int main(){
int aa[5] = {5, 4, 9, -1, 3};
int bb[2] = {16, -11};
int cc[7];
merge(aa, bb, cc, 5, 2);
return 0;
}
void merge(int *aa, int *bb, int *cc, int m, int n){
int i = 0, j = 0, k = 0;
while(i < m && j < n){
if(aa[i] < bb[j])
cc[k++] = aa[i++]; /*Smallest value should be assigned to cc*/
else
cc[k++] = bb[j++];
}
while(i < m) /*Transfer the remaining part of longest array*/
cc[k++] = aa[i++];
while(j < n)
cc[k++] = bb[j++];
}
The cc array is correctly filled, but the values are not ordered. Instead of the expected cc = {-11, -1, 3, 4, 5, 9, 16} it returns cc = {5, 4, 9, -1, 3, 16, 11}.
Like the assignments cc[k++] = aa[i++] and cc[k++] = bb[j++] do not work, somehow, or the logical test if aa[i] < bb[j] goes ignored.
I hypothesized operators priority problems, hence I tested with two different standard, with no differences:
gcc main.c -o main.x -Wall
gcc main.c -o main.x -Wall -std=c89
I checked the code many times, unable to find any relevant error. Any suggestion at this point would be appreciated.
You need to think your algorithm through properly. There's no obvious bug in it. The problem is your expectations. One way to make this clear is to think about what would happen if one array was empty. Would the function merge change the order of anything? It will not. In fact, if two elements a and b are from the same array - be it aa or bb - and a comes before b in that array, then a will also come before b in cc.
The function does what you expect on sorted arrays, so make sure they are sorted before. You can use qsort for this.
Other than that, when you use pointers to arrays you do not want to change, use the const qualifier.
void merge(const int *aa, const int *bb, int *cc, int m, int n)
There's no bug in your implementation (at least I don't see any, imho) The problem is that the merging you have done is not for two sorted arrays (it's for several bunches of sorted numbers). Case you had feed two already sorted arrays you'd have the result sorted correctly.
The merge sorting algorithm begins with splitting the input into two parts of sorted arrays. This is done by switching arrays when you detect the element is not in order (it is not greater to last number) You get the first ordered set to fill an array (the first a elements of initial list which happen to be in order, to put into array A, and the second bunch of elements to put them into array B. This produces two arrays that can be merged (because they are already in order) and this merging makes the result a larger array (this fact is what warrants the algorithm will make larger and larger arrays at each pass and warrants it will finish at some pass. You don't need to operate array by array, as at each pass the list has less and less packs of larger bunch of sorted elements. in your case:
1st pass input (the switching points are where the input
is not in order, you don't see them, but you switch arrays
when the next input number is less than the last input one):
{5}, {4, 9}, {-1, 3}, {16}, {-11} (See note 2)
after first split:
{5}, {-1, 3}, {-11}
{4, 9}, {16}
after first merge result:
{4, 5, 9}, {-1, 3, 16}, {-11}
after second pass split:
{4, 5, 9}, {-11}
{-1, 3, 16}
result:
{-1, 3, 4, 5, 9, 16}, {-11}
third pass split:
{-1, 3, 4, 5, 9, 16}
{-11}
third pass result:
{-11, -1, 3, 4, 5, 9, 16}
The algorithm finishes when you don't get two bunches of ordered streams (you don't switch arrays), and you cannot divide further the stream of data.
Your implementation only executes one pass of merge sorting algorithm you need to implement it completely to get sorted output. The algorithm was designed to make it possible to do several passes when input is not feasible to put in arrays (as you do, so it doesn't fully illustrate the thing with arrays). Case you have it read from files, you'll see the idea better.
NOTE
Sort programs for huge amounts of data use merging algorithm for bunchs of data that are quicksort'ed first, so we start with buckets of data that don't fit in an array all together.
NOTE 2
The number 16 after number 3 should have been in the same bunch as previous bunch, making it {-1, 3, 16}, but as they where in different arrays at first, and I have not found any way to put them in a list that splits into this arrangement, I have forced the buckets as if 16 < 3, switching artificially the arrays on splitting the input. This could affect the final result in making an extra pass through the data, but doesn't affect the final result, which is a sorted list of numbers. I have made this on purpose, and it is not a mistake (it has no relevance to explain how the algorithm works) Anyway, the algorithm switches lists (I don't like to use arrays when describing this algoritm, as normally merging algorithms don't operate on arrays, as arrays are random access, while lists must be accessed by some iterator means from beginning to end, which is the requirement of the merging sort algorithm) The same happens to {4, 9}, {16} after the first split, just imagine the result of the comparisons was the one shown, as after the first merge everything is correct.
If your program works fine, you can sort in O(N) by comparison. As it is not possible and mentioned in comments by #Karzes, your program works fine just for the sorted sub arrays. Hence, if you want to implement merge function for the merge sort, you should try your program for these two inputs:
int aa[5] = {-1, 3, 4, 5, 9};
int bb[2] = {-11, 16};
Not the most efficient cause it's bobble sort...
#include<stdio.h>
void merge(int *, int *, int *, int, int);
void sortarray(int array[], int arraySize)
{
int c,d,temp;
for (c = 0 ; c < arraySize-1; c++)
{
for (d = 0 ; d < arraySize - c - 1; d++)
{
if (array[d] > array[d+1]) /* For decreasing order use < */
{
temp = array[d];
array[d] = array[d+1];
array[d+1] = temp;
}
}
}
}
int main(){
int aa[5] = {5, 4, 9, -1, 3};
int bb[2] = {16, -11};
int cc[7];
int i;
sortarray(aa,sizeof(aa)/sizeof(aa[0]));
sortarray(bb,sizeof(bb)/sizeof(bb[0]));
merge(aa, bb, cc, 5, 2);
for(i=0;i<sizeof(cc)/sizeof(cc[0]);i++)
{
printf("%d,",cc[i]);
}
return 0;
}
void merge(int *aa, int *bb, int *cc, int m, int n){
int i = 0, j = 0, k = 0;
while(i < m && j < n)
{
if(aa[i] < bb[j])
cc[k++] = aa[i++]; /*Smallest value should be assigned to cc*/
else
cc[k++] = bb[j++];
}
while(i < m) /*Transfer the remaining part of longest array*/
cc[k++] = aa[i++];
while(j < n)
cc[k++] = bb[j++];
}
As I have found it very difficult to manipulate 2 dimensional arrays in C, I've decided to try and write a function that will take my 2D array and convert it to a 1D array. For the 2D array below I'd like it to translate to some thing like 1D_array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }.
I came across a very similar question on stack exchange, linked below, and have used the suggested code.
Convert 2D array to single array
The code I'm using is:
#define KP_ROWS 4
#define KP_COLS 4
static Uint16 KP_TEST_Keys[KP_ROWS][KP_COLS] = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 }
};
void main()
{
Uint16 array1D[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
memcpy(array1D, KP_TEST_Keys, sizeof(Uint16) * KP_ROWS * KP_COLS);
}
Again my overall goal is to convert the 2D array to a 1D array.
EDIT: After clearing errors from before I have edited and just now tested the above code and it works! array1D contains the data in the format I wanted.
Am I using memcpy correctly?
OK, but prone to failure as the size of array1D is not certainly tied to the size of KP_TEST_Keys.
Uint16 array1D[KP_ROWS*KP_COLS] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} ;
// Recommend size of destination, not size of source
// Ideally, it would be the minimum of the size of source and destination.
memcpy(array1D, KP_TEST_Keys, sizeof array1D);
As #Kurokawa Masato commented, memcpy() must be used in a function.
Suggest using standard types like uint16_t rather than Uint16.
The 2D array data is already stored contiguously in the order you require of your 1D array; there is no need at all to duplicate the data in a separate array; you only need cast the 2D array as follows:
Uint16* array1D = (Uint16*)KP_TEST_Keys ;
This provides a 1D array view of the 2D array without copying the data. Changes to the 1D view change the 2D data directly so there is no need to copy to and from the two representations.
If the 1D array view is to be read-only you can enforce that by:
const Uint16* array1D = (const Uint16*)KP_TEST_Keys ;
Further if the 1D array is to be locked to the 2D array and not to be capable of reassignment to some other array then:
Uint16* const array1D = (Uint16* const)KP_TEST_Keys ;
or both combined ( a constant pointer to constant data):
const Uint16* const array1D = (const Uint16* const)KP_TEST_Keys ;
One significant difference here is that sizeof(array1D) is the size of the pointer, not the size of the array; you should use sizeof(KP_TEST_Keys) for both.
If either if these declarations is made at file scope after the declaration of KP_TEST_Keys, the 1D view will exist with the same lifetime and scope as the 2D:
static Uint16 KP_TEST_Keys[KP_ROWS][KP_COLS] = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 }
};
static Uint16* array1D = (Uint16*)KP_TEST_Keys ;
You can also perform the cast directly at point of use rather then introducing a new variable to access individual elements such as:
Uint16 element = ((Uint16*)KP_TEST_Keys)[i] ;
where i is the 1D index 0 to sizeof(KP_TEST_Keys) - 1.
I have declared a 2D global array variable like so:
int grid_2d_array[ROWS][COLUMNS];
then in main I've to initialize it with hard-coded values:
grid_2d_array[ROWS][COLUMNS] = {{5, 7, 2, 8, 3, 6, 1, 4},
....
{1, 6, 3, 2, 4, 8, 9, 5}
};
Example:
#include <stdio.h>
#define ROWS 9
#define COLUMNS 9
/* Global variable. */
int grid_2d_array[ROWS][COLUMNS];
int main()
{
/* Initialze the 2D array. */
grid_2d_array[ROWS][COLUMNS] = {{5, 7, 2, 8, 3, 6, 1, 4},
....
{1, 6, 3, 2, 4, 8, 9, 5}
};
return 0;
}
But when I try compiling the source code, GCC gives the following error:
source_file.c: In function ‘main’:
source_file.c:45:34: error: expected expression before ‘{’ token
grid_2d_array[ROWS][COLUMNS] = {{5, 7, 2, 8, 3, 6, 1, 4},
^
I'm not sure why GCC is not recognizing grid_2d_array as a global variable.
The problem goes away if I redeclare the aforementioned variable in main.
I'm running GCC version: gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04)
C and C++ arrays can be initialized only as a part of the definition statement:
int grid_2d_array[ROWS][COLUMNS] = {{5, 7, 2, 8, 3, 6, 1, 4},
....
{1, 6, 3, 2, 4, 8, 9, 5}
};
Assignment of multiple values into an array is not supported.
In addition to FireAphis's answer, if you are under C99 you can initialize a pointer to array of ints (not a 2D array) outside his definition using compound literals:
int (*grid_2d_array)[COLUMNS]; /* Pointer to array of n int's */
in main:
grid_2d_array = (int [ROWS][COLUMNS]){
{5, 7, 2, 8, 3, 6, 1, 4},
{1, 6, 3, 2, 4, 8, 9, 5}
};