I am working on a project in C and have stumbled upon a few questions that I hope you fine folks can help me with! The project is just manipulating coordinate points that the user creates via standard input. I've included the different files and their functions below;
//points.h
struct Point{
int x;
int y;
}
//reads points from stdinput into our points array
int pointReader(struct Point points[]);
///////////////
//points.c
void pointReader(struct Point points[]){
//points[] is originally empty array (filled with NULLS)
struct Point point;
char buffer[10];
printf("X Coordinate:");
fgets(buffer, 10, stdin);
point.x = (int)buffer;
printf("Y Coordinate:");
fgets(buffer, 10, stdin);
point.y = (int)buffer;
append(points, point);
}
static void append(struct Point points[], struct Point point){
int i;
for (i = 0; i < 10; i++){
if (points[i] == NULL){
points[i] = point;
}
Upon compilation, I am receiving the following errors and I'm not too sure why:
points.c:115:10: error: invalid storage class for function 'append'
points.c: In function 'append':
points.c:127:17: error: invalid operands to binary == (have 'struct Point' and 'void *')
Also, can I so easily 'toss' around the points[] array like I am attempting to do?
Thanks for any comments!
The first error is most likely because you haven't declared the function append before you call it. Add a function prototype before you call it. In other words, before the pointReader definition, add the following line:
static void append(struct Point points[], struct Point point);
The second error is because the values in the points array are not pointers, and can therefore not be treated like pointers (like comparing it to NULL). You have to use another method of checking if an entry in the array is used or not. For example using the x and y values of -1 or something similar.
You also have another problem, and that is that you can't convert a string to an integer by just casting. You have to use a function such as strtol for that:
point.x = (int) strtol(buffer, NULL, 10);
Related
My main function has this:
int main() {
//
double minW, minL, width, length;
unsigned tileCap = 10;
auto *tiles = (Tile*)calloc(tileCap, sizeof(Tile) );
GetInput(&minW, &minL, &tiles, &tileCap);
}
And my GetInput() will read and save into the array of Tiles:
void GetInput(double *w, double *l, Tile **tiles, unsigned *tileCap) {
//
printf("Tile:\n");
double tileSize, tileJoint;
int argc;
unsigned tileCount = 0;
do {
argc = scanf("%lf %lf", &tileSize, &tileJoint);
if (tileSize == 0 || !CorrectSize(tileSize) || !CorrectSize(tileJoint) || argc != 2)
BadInput();
bool needTransform = HasFloatingPoint(tileSize);
if(needTransform) {
tileSize = MultiplyByTen(tileSize);
tileJoint = MultiplyByTen(tileJoint);
}
tiles[tileCount]->size = (long long)tileSize;
printf("%lld\n", tiles[tileCount]->size);
tiles[tileCount]->joint = (long long)tileJoint;
if(++tileCount == *tileCap) {
DoubleArray(tiles, tileCap); //f() with realloc
}
} while(argc != EOF);
}
This program works for first iteration of inputs but always gives exit code 11 and the debugger says BAD_ACCESS at the assignment.
So either I'm accessing or allocating the array incorrectly.
I give my function a double pointer. So in order to access Tile members, I need to dereference it twice. One dereference is [] and the other one is ->. Printing the Tile after assigning confirms it.
And I see nothing wrong with my allocation. Where am I wrong?
EDIT: tiles[index]->size would mean *(tiles[index]).size while I need (*tiles)[index].size. Dereference order and scope is important.
Even though your code seems incomplete and I'm mostly guessing, the issue seems to be in the following line in your main function:
GetInput(&minW, &minL, &tiles, &tileCap);
You should consider that tiles is already a pointer. When you're using &tiles, you're actually passing a pointer to your pointer and not the pointer itself.
In your GetInput function, you're using tiles[tileCount] which indicated you wanted to pass a pointer. If your GetInput was supposed to get a double pointer, you would have used (*tiles)[tileCount].
You can solve many of these issues by listening
I think what you probably meant to do was:
GetInput(&minW, &minL, tiles, &tileCap);
And the function definition should probably look like this:
void GetInput(double *w, double *l, Tile *tiles, unsigned *tileCap
EDIT: (using a double pointer)
Since you need to use a double pointer, than you should remember to dereference the double pointer when you're looking into the data. i.e.:
*(tiles)[tileCount]->size = (long long)tileSize;
printf("%lld\n", *(tiles)[tileCount]->size);
*(tiles)[tileCount]->joint = (long long)tileJoint;
Explanation:
A double pointer needs a double de-referencing. The first dereferencing collects the information on the nested pointer (*tiles) and the second dereferencing collects the data (**tiles).
The double dereferencing can also be achieved using the square brackets ((*tiles)[i] or tiles[0][i]).
Since tiles is a struct you can use the "arrow" as the second dereferencing technique as well: (*tiles)->size
I am trying to declare a data structure in c and set some variables but I'm having a bit of trouble.
struct point {
float *x;
float *y;
float *z;
};
this struct is 24 bytes long so that's fine by me.
const unsigned int sz = 1<<24;
struct point _points[sz];
for(int i = 0; i < sz; ++i)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
// get_rand_float() returns a pointer to float;
The problem that I am having is that the application will crash.
I playing with the code a bit it seems that maybe 1<<24 is too large? Bringing it down to 1<<14 the program runs just fine.
That brings me to another question, why would 1<<24 or about 16 million ints cause my program to crash? It's a fairly trivial program just int main boilerplate and this struct?
You don't want a structure of pointers to floats:
struct point {
float *x;
float *y;
float *z;
};
You want a structure of floats:
struct point {
float x;
float y;
float z;
};
In your code, sz is int variable, not an array. So, techinicaly you cannot use the array subscript operator on sz. That code should not compile.
Maybe, you wanted to write something like
_points[i].x = get_rand_float();
But then again, it depends on get_rand_float() return type. It has to return a float * (which is not very likely seeing the function name).
In case, if get_rand_float() returns afloat value, and you want to store the returned value, then you don't need to use pointers as your structure member variable. You can simply use float x; and so on.
One possible problem is that your array of points is too large for the stack. See here. You could fix that by a dynamic memory allocation, something like:
struct point *_points = malloc(sz*sizeof(struct point));
And of course, don't forget to free the memory when finished.
EDIT: Based on your edit, your crash occurs when you use a massive struct size (1<<24), or 16,777,216 items in the struct. Borrowing an answer from here:
Size limitation of C structure
It would appear that you may be violating C standard by having over 65535 bytes in an object. Since 1<<14 works, which is only 16384, that might be why. To verify, try using anything above 1<<16 - those should all crash because it would be over 65535.
On a side note, it would be helpful if you post the actual error message you get so we have a better idea of what is going on. :)
---Pre-Author Edit Answer---
Assuming get_rand_float() returns what it's supposed to, the problem is that sz is an int, not a struct. It should look like:
int sz = 24;
struct point _points[sz];
for(int i = 0; i < sz; ++i)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
Others have pointed out your two main problems (size too large, and you should be using float not float* in your struct). But there is another potential problem, too: you should not get into the habit of beginning an identifier name with an underscore, because, from Section 7.1.3 of the 1999 C standard:
All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.
All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces.
Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included; unless explicitly stated otherwise (see 7.1.4).
All identifiers with external linkage in any of the following subclauses (including the future library directions) are always reserved for use as identifiers with external linkage.154
Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included.
Keeping apart the big size of the array,your program is mainly crashing because there no memory allocated to the pointer variables x,y and z.
You have to allocate memory to the variables before assigning any values.
for(int i = 0; i < sz; ++i)
{
sz[i].x = get_rand_float(); <--- getting crash here!
sz[i].y = get_rand_float();
sz[i].z = get_rand_float();
}
for(i=0;i<sz;i++)
{
_points[i].x =(float *) malloc(sizeof(float));
_points[i].y = (float *) malloc(sizeof(float));
_points[i].z = (float *) malloc(sizeof(float));
*( _points[i].x) = get_rand_float();
*( _points[i].y) = get_rand_float();
*( _points[i].z) = get_rand_float();
}
for(i=0;i<sz;i++)
{
printf("%f %f %f ",*( _points[i].x), *(_points[i].y), *(_points[i].z));
printf("\n");
}
You can make your program simple by taking float as members of the structure instead of float pointers.
struct point {
float x;
float y;
float z;
};
int main()
{
int i;
for(i=0;i<sz;i++)
{
_points[i].x = get_rand_float();
_points[i].y = get_rand_float();
_points[i].z = get_rand_float();
}
for(i=0;i<sz;i++)
{
printf("%f %f %f ", _points[i].x, _points[i].y, _points[i].z);
printf("\n");
}
working on a c project and I've hit a roadblock. I'm trying to print the point coordinate style, and I've included all the code necessary to help you folks help me out!
//point.h
struct Point{
char label;
int x;
int y;
};
//point.c
displayPoint(struct Point p){
char label = p.label;
int x = p.x;
int y = p.y;
// label: (x, y)
printf("(%c: (%d, %d)", label, x, y);
}
//build point from standard input
readPoint(){
struct Point point;
printf("Enter label (character): ");
fgets(buff, MAX_LINE, stdin);
point.label = buff; //I think this is the issue here
printf("Enter x:");
fgets(buff, MAX_LINE, stdin);
point.x = (int) strtol(buff, NULL, MAX_LINE);
printf("Enter y:");
fgets(buff, MAX_LINE, stdin);
point.y = (int) strtol(buff, NULL, MAX_LINE);
Upon compilation, I receive the following error:
points.c: In function 'displayPoint':
points.c: warning: initialization makes pointer from integer without a cast [enabled by default]
points.c: warning: format '%c' expects argument of type 'int', but argument 2 has type 'char *' [-Wformat]
points.c: In function 'readPoint':
points.c: warning: assignment makes integer from pointer without a cast [enabled by default]
If I create a Point using the following information:
Label: A
x: 2
y: 3
and run displayPoint I get this output:
R: (2, 3)
Obviously that's wrong, I don't know where the R came from. What am I missing here? Why does C have to be so stubborn, this would be so simple to do in java, python, etc
You've got a couple of problems here:
fgets gets a buffer, not a single character. I hope buff is declared as a character array (char buff[MAX_LINE]).
Your struct declares a single character for its label, but you're assigning your buffer to the character.
You're reusing the buffer. Because this is just a pointer to a chunk of memory, you're potentially clobbering old data. You might (read, probably will want to) reset your buffer between uses.
Given this, I think what you intend is this:
point.label = buff[0];
I'm guessing you just want a single character for your label, in which case this should work and you won't be clobbering that value. (I don't know about the rest of your input.)
You cannot perform such asignment:
point.label = buff;
buff is an array and label is a character. You may use memcopy but if you need a label in your struct put an array there so that you can store it there. In a character you may store 1 character only.
point.label = buff //I think this is the issue here
Do you see a semi-colon on the end of that line?
Don't C statement end with semi-colons?
Same here:
struct Point{
char label;
int x;
int y;
}
Struct declarations should end with a semi-colon.
This question already has answers here:
Manipulate multidimensional array in a function
(4 answers)
Closed 8 years ago.
I have read several posts related to my question on C. This indeed help me cut down on my errors. However, I'm still having problems that other posts couldn't solve for me. Basically, this is what I am trying to do.
Define an array in main. I pass in a pointer to this array to a function. This function will open up a file, parse that file, and put information from that file into the array whose pointer I passed in. Well, it fails.
The errors I get are:
work.c:12: error: array type has incomplete element type
work.c: In function ‘main’:
work.c:20: error: type of formal parameter 1 is incomplete
work.c: At top level:
work.c:25: error: array type has incomplete element type
The entire code follows below. But I think you only need to focus on how I defined my array, and pointer, and so on.
#include <stdio.h>
#include <stdlib.h>
//Defining Preprocessed Functions
char readFile(char array[][], int, int);
//void displayStudentInfo(int*);
//Implements Step 1 and 2 of Student Instuctions
int main(int argc, char* argv[])
{
int x = 256;
int y = 256;
char arrays[x][y];
readFile(&arrays,x,y);
//displayStudentInfo(&array);
return 0;
}
char readFile(char array[][], int x, int y)
{
char line[256]; //Three columns 0, 1, 2 corresponds to firstname, lastname, score.
char* string;
int columns = 3;
x = 0;
//int y; //Defines rows and columns of 2D array to store data
//char array[x][y]; //Defines the array which stores firstname, lastname, and score
FILE *file;
file = fopen("input.txt", "r");
//Test to make sure file can open
if(file == NULL)
{
printf("Error: Cannot open file.\n");
exit(1);
}
else
{
while(!feof(file))
{
/*
if(fgets(line, 256, file))//fgets read up to num-1 characters from stream and stores them in line
{
printf("%s", line);
}
*/
if(fgets(line,256,file)!=NULL)
{
for(y = 0; y < columns; y++)
{
array[x][y]=strtok(fgets(line,256,file), " ");
}
x++;
}
}
}
fclose(file);
}
You have a few problems. The first two are similar:
First, you're using an unbounded array in your function declaration: the compiler needs to know more about the argument, i.e. the dimensions. In this case it's sufficient to provide one of the dimensions:
char readFile(char array[][NUM_Y], int, int);
Now the compiler has enough information to handle the array. You can leave off a dimension like this, but it's usually better to be explicit, and declare the function as:
char readFile(char array[NUM_X][NUM_Y], int, int);
Next, when you're declaring your arrays array in main, you'll need to be more specific about dimensions - similar to the argument list for the function:
char arrays[x][NUM_Y];
Choose NUM_Y to be more than large enough fit the amount of data that you'll expect.
Next, you're not initializing x and y in main, then you go on to declare an array using those variables. This is bad because these variables can contain any garbage value, including 0, and so you'll end up with an array of unexpected dimensions/size.
Finally, when you pass the array to your function, don't de-reference it, just pass along the variable:
readFile(arrays, x, y);
In C, when you pass an array to a function, what is actually passed is a pointer to the first element. This means that the array isn't copied, and so the function has access to the area of memory that it expects to change. I'll guess that you're de-referencing because that's the way that you've learned to pass simpler types that you want to change in the function, like ints or structs, but with arrays you don't need to do this.
char arrays[x][y]; : x,y must be constants or actual values, not variables: http://www.acm.uiuc.edu/webmonkeys/book/c_guide/1.2.html#arrays
You can workaround this limitation by declaring a pointer instead and assign it to the address returned when reserving the memory needed using malloc(sizeof(byte)*y) x times, on each position reserved by malloc(sizeof(byte)*x): http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.13.html#malloc
In the definition
char arrays[x][y];
y should be always a const. There is absolutely no exception for this. Other dimension - x can be a variable when you define object on the stack on some of the compilers only.
I'm wondering what's the difference between sample1 and sample2. Why sometimes I have to pass the struct as an argument and sometimes I can do it without passing it in the function? and how would it be if samplex function needs several structs to work with? would you pass several structs as an argument?
struct x
{
int a;
int b;
char *c;
};
void sample1(struct x **z;){
printf(" first member is %d \n", z[0]->a);
}
void sample2(){
struct x **z;
printf(" first member is %d \n", z[0]->a); // seg fault
}
int main(void)
{
struct x **z;
sample1(z);
sample2();
return 0;
}
First of all, your argument type is not struct, but a pointer to pointer to struct (or an array of pointers to struct - these are semantically equivalent from the callee's point of view, except that the address of an array can't be changed).
In the second case you use a local variable that is totally independent of the one with same name in main. Since it is not initialized, you get a seg fault when trying to access one of its members. (The one in main is not initialized either, but accessing it just seems to work by chance in sample1).
You should initialize your variables before using them, otherwise you enter the territory of undefined behaviour. E.g.
void sample1(struct x **z){
printf(" first member is %d \n", z[0]->a);
}
void sample2(){
struct x z[1];
z[0].a = 1;
...
printf(" first member is %d \n", z[0].a);
}
int main(void)
{
struct x z[1];
z[0].a = 1;
...
sample1(z);
sample2();
return 0;
}
Both are invalid and accessing bad memory. The results are undefined so both results are correct.
C and C-like languages have a concept of "scope". See all those curly braces ({ and })? Those are "blocks". They essentially wrap all the code between them into bundles that are independent of any other blocks at the same level. Any variable you create in that block is only accessible within that block—you can't reference it anywhere else.
You can create a nested block. For example:
int f() {
int x;
scanf("%d", &x);
if (x == 3) {
return 7;
}
else {
return x;
}
}
As you can see, the else block is nested inside the function's block, and so can access the function's variables.
When you declare struct x **z in both main and sample2, you're actually creating two variables, both called z. These are totally independent—they're not the same variable at all. They're not related. The only thing they have in common is their name and type—the actual value is different. The only way you can use the same variable in both is by passing, as you do in sample1.
Of course, currently, your z pointer is garbage—you haven't allocated anything. I'd recommend you actually store something in there before you try and dereference it.
Your declaration
struct x **z;
simply creates a pointer to a pointer to a structure of type x. You're not actually initialising the pointers, i.e. making them point anywhere.
Try something like
struct x z;
struct x *pZ = &z;
sample1(&pZ);
(I'm not completely sure what you're actually trying to achieve, though!)