I get the error
subscripted value is neither array nor pointer
when I try to compile my program. I understand it has something to do with the variable not being declared but I checked everything and it seemed to be declared.
static char getValue(LOCATION l)
{
/*return carpark[l.col][l.row]; // Assumes that location is valid. Safe code is
below:
*/
if (isValidLocation(l)) {
return carpark[l.col][l.row]; <<<<<<<< this line
} // returns char if valid (safe)
else {
return '.';
}
Which corresponds to this part of the code in the header
typedef struct
{
/* Rectangular grid of characters representing the position of
all cars in the game. Each car appears precisely once in
the carpark */
char grid[MAXCARPARKSIZE][MAXCARPARKSIZE];
/* The number of rows used in carpark */
int nRows;
/* The number of columns used in carpark */
int nCols;
/* The location of the exit */
LOCATION exit;
} CARPARK;
Carpark was declared in the main prog with:
CARPARK carpark.
Thanks for the help.
carpark is not an array so you probably want something like:
return carpark.grid[l.col][l.row];
The error message is telling you exactly what the problem is. The variable carpark is neither an array nor a pointer, so you cannot apply the [] operator to it.
carpark.grid, however, is an array, so you could write
return carpark.grid[l.col][l.row];
Related
I'm in trouble with reading a data from a csv-file and parsing it into a struct. I think its best to show some code.
This is my struct:
typedef struct MyStruct{
char text[150];
char attr[4][50];
char check;
short int num;
} t_mystruct;
A sample line in my file could look like this: This is a long text;brown;green;yellow;silent;X;13;
Now I want to read that file and add that data to an array:
list = malloc(sizeof(t_mystruct) * LIST_SIZE); /* Allocating Memory */
for (i = 0; i < LIST_SIZE; i++) /* Adding data to list */
{
t_mystruct element;
if (fscanf(fp, "%149[^;];%49[^;];%49[^;];%49[^;];%49[^;];%49[^;];%[^;];%d;", &element.text, &element.attr[0], &element.attr[1], &element.attr[2], &element.attr[3], &element.check, &element.num) != 7)
break; /* Break ==> Incomplete line/data */
list[i] = element; /* Add to list */
}
This works, but I face two problems:
The "num" value isn't the same value as in my file. I get results from 49 up to around 13000, but they never match my actual input value (13 in my example).
The code belongs to a "readFile" function. At the end of that function, I face a "stack around the variable "element" was corrupted" error. Edit: When debugging, I can continue and the program works as expected.
But I can't see my mistakes.
You have specified five format specifiers of
%49[^;];
but your struct has only four, and you only provide four arguments to match. You are also reading the last value as int, when it is short.
**Issue overview **
The current issue i have is that i have an array which has the size of a variable which happens to be the amount of lines in a file. This is an integer which is calculated and returned, which becomes the arraysize (e.g. file text.txt has 12 lines so the array is of size 12).
I want to know how i can return this value to another c file for use in a function so i can loop through the complete array.
points to note
I am not allowed any globals at all in this assignment, no global arrays/variables at all.
The line counting functions works correctly so i will not be posting it here
The array is set up correctly and print the correct results
Most of the code from the functions has been removed to make it easier to read.
The correct #includes for each file are present, i just need an example of how to do it.
The code:
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
/* i want to return the value of no_of_lines *?
I want to return the value of no_of_lines
The c file where i need the value
/*This is where i need the variable */
void asign_mayday_to_ships() {
int* ship_arr_length = SIZE OF SHIP ARRAY NEEDED
mayday_call* mday_ptr;
ship* ship_ptr; /* this is a ship array */
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int i;
for(i = 0; i < SIZE OF SHIP ARRAY; i++){
}
Just pass both pointer and size, it'a a C way.
void read_from_file() {
/* reading and parsing removed */
no_of_lines = (count_lines(locof) - 1);
/* locof is a char array storing the file name */
ship ships[no_of_lines];
some_fun_from_second_file(ships, no_of_lines);
Who calls the two fnctions? Can't you just return the nr of lines in an upper function then pass it in the second one? If not, then you must somehow store it in a variable(or a struct member) and then you can grab it later. This is a contextual solution, it might not work for you.
i had to first malloc my ships array, then set the size of the malloc depending on the amount of elements then i can return the size of the pointer:
ship* ships;
ships = malloc(sizeof (ship) * no_of_lines);
the in the function i was having trouble with:
mayday_call* mday_ptr;
ship* ship_ptr;
mday_ptr = read_mayday_file();
ship_ptr = read_ship_locations();
int arr_size = sizeof (ship_ptr) ;
int i;
for(i =0; i < arr_size; i++) {
//do something
}
`
sounds like your 'teacher' wants make you use a sentinel value. Ie put an object at the end of the array that cannot exist (a ship with name all spaces for example) then in the array processing you keep looping till you hit the magic value.
This is a bad design, but if you aren't allow globals and you aren't allow parameters I cant see what else to do
The following function, populateArpeggioArray, takes a pointer to a typedef'd struct containing several members, the identities of which are not necessarily relevant to the issue that I have. populateArpeggioArray should perform a few operations on the internal elements of the structure before passing a pointer to the struct to the function sortNoteStack.
What I've found is that the struct is never operated upon by sortNoteStack, because populateArpeggioArray, at some point, changes the value of the pointer to the struct before passing the changed value to sortNoteStack.
As far as I can tell, the code seems to be formatted properly, with proper pointer dereferencing for all operations performed on the elements of the struct. From what I can see, none of the lines of code should be able to modify the value of the pointer to the struct. Declaring the struct with the const prefix does not help, as its members are therefore also locked to a fixed value.
I'm open to the idea that this may be a problem with the simulator, and not the code, but if there is some latent issue with the code I have written, I'd certainly like to understand what I'm doing incorrectly.
Thank you for your help.
-Nick
void populateArpeggioArray(arpeggio* arp) {
uint8_t i = 0,j=0, newNoteFlag=0;
for(i=0; i<12; i++) {
newNoteFlag = 0;
if(globals.keyboardCurrentState[i]) { /* Check to see if the current state shows that a keyboard button is pressed. */
arp->sequenceLength++; /* Temporarily increase the sequence length */
for(j=0;j < arp->sequenceLength;j++) { /* Check the pitch of each note currently in the note stack */
if(globals.keyboardNotes[i] == arp->notesUnordered[j].pitch) { /* If the currently selected note is already present in the note stack, */
arp->sequenceLength--;
newNoteFlag = 1; /* undo the temporary sequence length increase */
}
}
if(!newNoteFlag) {
arp->notesOrdered[arp->sequenceLength].pitch = globals.keyboardNotes[i]+liveArpeggio.transposeShift;
arp->notesUnordered[arp->sequenceLength].pitch = globals.keyboardNotes[i]+liveArpeggio.transposeShift; /* Add the new pitch to the appended note */
arp->notesOrdered[arp->sequenceLength].length = 111;
arp->notesUnordered[arp->sequenceLength].length = 111; /* Give the new note a default length. TEMP */
}
}
}
sortNoteStack(&arp);
}
With sortNoteStack(&arp), you're passing the address of the pointer, not the address of the struct. You want to pass the address of the struct (the value of the pointer). Thus, use sortNoteStack(arp).
In the hope of gaining a better understanding of the answers
given in this post, can someone please explain to me if the
following circular buffer implementation is possible, and if
not, why not.
#define CB_TYPE_CHAR 0
#define CB_TYPE_FLOAT 1
...
typedef struct CBUFF
{
uint16 total; /* Total number of array elements */
uint16 size; /* Size of each array element */
uint16 type; /* Array element type */
uint16 used; /* Number of array elements in use */
uint16 start; /* Array index of first unread element */
void *elements; /* Pointer to array of elements */
} CBUFF;
...
void cbRead(CBUFF *buffer, void *element)
{
if (buffer->type == CB_TYPE_CHAR)
{
/* The RHS of this statement is the problem */
*(char*)element = *(buffer->elements[buffer->start]);
}
/* Other cases will go here */
buffer->start = (buffer->start + 1) % buffer->total;
--buffer->used;
}
I understand that the LHS must be cast to char so that I can
dereference the void pointer. I also understand that this code
fragment:
buffer->elements[buffer->start]
gives the address of the 'buffer->start' element of the elements
array, which I also want to dereference in order to get to the
content of that address. Or at least that's what I take from
K&R.
Given all that, how do I tell the compiler that the content of
the memory at that address is a char, and that it is okay to
dereference it? There is something going on here I just don't
understand.
buffer->elements is also a void * so you need to cast it before you can do anything with it:
*(char*)element = ((char *)buffer->elements)[buffer->start];
Given all that, how do I tell the compiler that the content of the memory at that address is a char, and that it is okay to dereference it?
Well, you've already done it on the LHS of that line:
*(char*)element = *(buffer->elements[buffer->start]);
To derefence buffer->elements[n] you will need to cast that as well.
*(char*)element = *((char*)buffer->elements)[buffer->start];
Now the question is whether or not that cast is correct. I can't tell you that as you did not post the initialization of buffer->elements.
I need to store an array of point (x,y). I read the points from a file, and the number of points are not constant, but i can get it at the first line of the file. So i write a procedure load() to loading the points from the file and store them in a global array. It doesn't work.
My code:
int *array[][]; // this is a pointer to a 2-dimensional array??
void load(){
..
int tempArray[2][n]; //n is the first line of the file
..
array = tempArray;
}
You're trying to return a pointer to memory that is local to the function that defines the variable. Once that function stops running ("goes out of scope"), that memory is re-used for something else, so it's illegal to try and reference it later.
You should look into dynamic allocation, and have the loading function allocate the needed memory and return it.
The function prototype could be:
int * read_points(const char *filename, size_t *num_points);
Where filename is of course the name of the file to open, num_points is set to the number of points found, and the returned value is a pointer to an array holding x and y values, interleaved. So this would print the coordinates of the first point loaded:
size_t num_points;
int *points;
if((points = load_points("my_points.txt", &num_points)) != NULL)
{
if(num_points > 0)
printf("the first point is (%d,%d)\n", points[0], points[1]);
free(points);
}
This declaration of yours does not work:
int *array[][]; // this is a pointer to a 2-dimensional array??
First, it is trying to declare a 2D array of int *. Second, when you declare or define an array, all dimensions except the first must be specified (sized).
int (*array)[][2]; // This is a pointer to a 2D array of unknown size
This could now be used in a major variant of your function. It's a variant because I misread your question at first.
void load(void)
{
...
int tempArray[n][2]; // Note the reversed order of dimensions!
...
array = &tempArray;
...there must be some code here calling functions that use array...
array = 0;
}
Note that the assignment requires the & on the array name. In the other functions, you'd need to write:
n = (*array)[i][j];
Note, too, that assigning the address of a local array to a global variable is dangerous. Once the function load() returns, the storage space for tempArray is no longer valid. Hence, the only safe way to make the assignment is to then call functions that reference the global variable, and then to reset the global before exiting the function. (Or, at least, recognize that the value is invalid. But setting it to zero - a null pointer - will more nearly ensure that the program crashes, rather than just accessing random memory.
Alternatively, you need to get into dynamic memory allocation for the array.
Your question actually is wanting to make a global pointer to a VLA, variable-length array, where the variable dimension is not the first:
int tempArray[2][n]; // Note the reversed order of dimensions!
You simply can't create a global pointer to such an array.
So, there are multiple problems:
Notation for pointers to arrays
Initializing pointers to arrays
Assigning global pointers to local variables
You can't have global pointers to multi-dimensional VLAs where the variable lengths are not in the first dimension.
You should minimize the use of globals.
A more elegant version might go like this:
typedef struct point_ { int x; int y; } point;
point * create_array(size_t n)
{
return calloc(n, sizeof(point));
}
void free_array(point * p)
{
free(p);
}
int main()
{
size_t len = read_number_from_file();
point * data = create_array(len);
if (!data) { panic_and_die(); }
for (size_t i = 0; i != len; ++i)
{
/* manipulate data[i].x and data[i].y */
}
free_array(data);
data = 0; /* some people like to do this */
}
You are trying to assign an array but in C arrays cannot be assigned.
Use memcpy to copy one array to another array. Arrays elements in C are guaranteed to be contiguous.
int bla[N][M] = {0};
int blop[N][M];
/* Copy bla array to blop */
memcpy(blop, bla, sizeof blop);