I am trying to implement an array implementation of a stack. I am new to stack and I have tried to implement the push operation in c, and here is my code:
#include "stack.h"
/**
* push_arr_stack - pushes an element to the stack
* #n: The number that will be pushed to the stack
*
* Return: It returns nothing
*
*/
void push_arr_stack(int n)
{
top = top + 1;
stack_arr[top] = n;
}
Here is my header file:
#ifndef STACK_H
#define STACK_H
#define MAX 4
extern int stack_arr[MAX];
extern int top = -1;
void push_arr_stack(int n);
#endif
And I have tried the push operation using the following test function:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include "stack.h"
/**
* main - Entry point for my program
*
* Return: On success, it returns 0,
* On error, it returns -1
*/
int main(void)
{
push_arr_stack(7);
return (0);
}
But I get the following error,
gcc -Wall -Werror -Wextra -pedantic -std=gnu89 main.c 0-push_arr_stack.c
In file included from main.c:4:
stack.h:6:12: error: ‘top’ initialized and declared ‘extern’ [-Werror]
6 | extern int top = -1;
| ^~~
cc1: all warnings being treated as errors
In file included from 0-push_arr_stack.c:1:
stack.h:6:12: error: ‘top’ initialized and declared ‘extern’ [-Werror]
6 | extern int top = -1;
| ^~~
cc1: all warnings being treated as errors
I need the top variable to track which index is the top of the stack, but it is giving me the error that top is initialized and declared. How can I make it so I can initialize top to -1
Either those variables should be local to stack.c or to the caller. They should not be declared at file scope (outside any function). By declaring something extern, you state that "this is allocated elsewhere". But you never actually allocate it elsewhere, hence the problems. Also, since it is allocated elsewhere, the initialization has to be placed elsewhere too.
However, using extern like this is very bad practice, since it creates global variables and spaghetti code, where one variable is shared across multiple files even though it shouldn't.
Instead you could place all those variables inside a struct. For beginner-level applications it is probably sufficient to just do like this:
// stack.h
typedef struct
{
int stack_arr[MAX];
int top;
} stack;
void stack_init (stack* s);
And then:
// stack.c
void stack_init (stack* s)
{
/* default initialization here */
s->top = -1;
}
Now the caller of your code can include stack.h, declare a variable stack my_stack; and then call your functions like stack_init(&my_stack);.
For professional applications, the above may not be considered good enough, since it violates the best design practice known as private encapsulation. The caller gets access to internal variables of the struct even though they shouldn't. In such cases one could implement opaque types to fix this: How to do private encapsulation in C?
The header file is included in two translation units: with main and with the function definition. So the variable top is defined twice.
In the header file just declare the variable
extern int top;
and in main define it like
int top = -1;
before the function main after the header.
Pay attention to that a variable declared in a file scope with the storage class specifier extern and with an initializer represents a definition of the variable. You may not define a variable with external linkage twice.
From the C Standard (6.9.2 External object definitions)
1 If the declaration of an identifier for an object has file scope and
an initializer, the declaration is an external definition for the
identifier.
Pay attention to that in general it is not a good approach to use global variables.
Related
I have a program consisting of two source files (farm.c, init.c) and two corresponding header files (farm.h, init.h) Both source files contain header guards and each other, because they both require functions/variables from each other.
init.h:
#ifndef INIT_H
#define INIT_H
#include<stdio.h>
#include<stdlib.h>
#include"farm.h"
#define PIG_SOUND "oink"
#define CALF_SOUND "baa"
enum types {PIG, CALF};
typedef struct resources {
size_t pork;
size_t veal;
size_t lamb;
size_t milk;
size_t eggs;
} resources;
typedef struct animal {
size_t legs;
char* sound;
int efficiency;
void (*exclaim)(struct animal*);
void (*work)(struct animal*, struct resources*);
} animal;
/* I have tried various ways of declaring structs in addition to
the typedef such as this */
//animal stock;
//animal farm;
void make_pig(struct animal* a, int perf);
void make_calf(struct animal* a, int perf);
#endif
farm.h:
#ifndef FARM_H
#define FARM_H
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include"init.h"
/* GCC does not recognise the typedef or struct identifier
until these forward declarations have been made in
addition to the included init.h header file */
//typedef struct animal animal;
//typedef struct resources resources;
void exclaim(animal* b);
void work(struct animal* b, struct resources* s);
#endif
init.c:
#include"init.h"
void make_pig(animal* a, int perf) {
a->legs = 4;
a->sound = PIG_SOUND;
a->efficiency = perf;
a->exclaim = exclaim;
a->work = work;
}
void make_calf(animal* a, int perf) {
a->legs = 4;
a->sound = CALF_SOUND;
a->efficiency = perf;
a->exclaim = exclaim;
a->work = work;
}
farm.c:
#include"farm.h"
int main() {
return 0;
}
void exclaim(animal* a) {
for (int i = 0; i < 3; i++) {
printf("%s ", a->sound);
}
printf("\n");
}
void work(animal* a, struct resources* r) {
if (!strcmp(a->sound, PIG_SOUND)) {
r->pork += a->efficiency;
}
if (!strcmp(a->sound, CALF_SOUND)) {
r->veal += a->efficiency;
}
}
Using both types of names (i.e.,struct ani and animal) normally works perfectly fine on my Linux system with the C99 standard. However when I use struct ani instead of animal here, I get the below warnings for every instance of the type usage for struct ani and struct resources.
lib/farm.h:10:21: warning: ‘struct ani’ declared inside parameter list will not be visible outside of this definition or declaration
10 | void exclaim(struct ani* a);
| ^~~
lib/farm.h:11:33: warning: ‘struct resources’ declared inside parameter list will not be visible outside of this definition or declaration
11 | void work(struct ani* a, struct resources* r);
And 10 warnings in total for every usage of function pointers of the form:
src/init.c:17:16: warning: assignment to ‘void (*)(struct ani *)’ from incompatible pointer type ‘void (*)(struct ani *)’ [-Wincompatible-pointer-types]
17 | a->exclaim = exclaim;
| ^
src/init.c:18:13: warning: assignment to ‘void (*)(struct ani *, struct resources *)’ from incompatible pointer type ‘void (*)(struct ani *, struct resources *)’ [-Wincompatible-pointer-types]
18 | a->work = work;
Can someone please explain why such behaviour occurs and how I can avoid problems? It typically takes me an unfeasible amount of time to solve these errors and I still don't truly understand my mistake in the first place.
You've hit one of the odd corner cases of C scoping rules.
Informally, a tagged struct (or union, but I'm not going to repeat that over and over) springs into existence when it is named if no declaration for it is visible. "Springs into existence" means that it is considered declared in the current scope. Also, if a tagged struct was previously named in a scope and you then declare a struct with the same tag, the two structs are considered the same. Until a declaration for the struct is completed, the struct is considered an incomplete type, but a pointer to an incomplete type is a complete type, so you can declare a pointer to a tagged struct before you actually complete the definition of the struct.
Most of the time, that just works with minimal thought. But function prototypes are a bit special, because a function prototype is a scope, all by itself. (The scope lasts only until the end of the function declaration.)
When you put that together, you end up with the issue you're facing. You cannot use a pointer to a tagged struct in a function prototype unless the tagged struct was known before the function prototype appears. If it had been mentioned before, even in an outer scope, the tag is visible and therefore will be considered to be the same struct (even if it is still incomplete). But if the tag was not previously visible, a new struct type will be created within the prototype scope, which will not be visible after that scope ends (which is almost immediately).
Concretely, if you write the following:
extern struct animal * barnyard;
void exclaim(struct animal*);
then the two uses of struct animal refer to the same struct type, which will presumably be completed later (or in another translation unit).
But without the extern struct animal * barnyard; declaration, the struct animal named in the exclaim prototype is not previously visible, so thus is declared only in the prototype scope, so it is not the same type as some subsequent use of struct animal. Had you put the declarations in the opposite order, you would have seen a compiler warning (assuming you'd asked for compile warnings):
void exclaim(struct animal*);
extern struct animal * barnyard;
(On godbolt, bless it's heart)
A typedef declaration performs the same way as the extern declaration above; the fact that it is a type alias is not relevant. What's important is that the use of struct animal in the declaration causes the type to spring into existence, and you can subsequently use it freely in a prototype. That's the same reason that the function pointers inside your struct definitions are OK; the start of the struct definition was sufficient to cause the tag to be declared, so the prototype sees it.
In fact, any syntactic construction which contains a tagged struct (struct whatever) will serve the same purpose, because what matters is the effect of mentioning a tagged struct with no visible declaration. Above, I used extern global declarations as examples because they are lines which might appear in a header, but there are many other possibilities, including even the declaration of a function which returns a pointer to a struct (because the return type of a function declaration is not in the prototype scope).
See below for some additional comments about the edited question.
My personal preference is to always use typedefs as forward declarations of tags, and never use struct foo anywhere in my code other than the typedef and the subsequent definition:
typedef struct Animal Animal;
void exclaim(Animal*);
// ...
// Later or in a different header
struct Animal {
Animal* next;
void (*exclaim)(Animal *);
// etc.
};
Note that I always use the same identifier for the tag and the typedef. Why not? There's no confusion and tags have not been in the same namespace as other identifiers since C was premordial.
For me, a big advantage of this style is that it lets me separate implementation details; the public header only contains the typedef declarations (and prototypes which use that type) and only the implementation needs to contain the actual definitions (after first having included the public header).
Note: since this answer was written, the question was edited to add a more detailed code sample. For now, I'll just leave these additional notes here:
On the whole, you get better answers when you provide better information. Since I couldn't see your actual code, I did the best I could, which was to try to explain what is going on, leaving you to apply that to your actual code.
In the code you have now added to the question, there is a circular header dependency. These should be avoided; it's almost impossible to get them right. The circular dependency means that you don't control the order of inclusion, so a declaration in one header might not come before the use in another header. You no longer have a forward declaration, because, depending on the inclusion order, it might be a backward declaration.
To resolve the circular dependency, abstract out the shared components and put them in a new header file. Here, forward declarations of structs (using, for example, typedefs) are highly useful because they don't depend on anything used in the definition of the struct. A shared header might include only typedefs, or it might also include prototypes which don't require additional dependencies.
Also, avoid putting long lists of library includes in your header files; include only those headers actually necessary to define types actually used in the header.
I need to define a global array which has to be visible in every file. I declared it in a header file, but it's stored in heap e not in stack. How can i put it in stack? Thank you
EDIT:
I'm using an ATMEGA32 and array is put at the begin of the RAM (address 0x0060), while I need to put it at the end (address 0x085F)
common.h
#define dimension 5
unsigned int board[dimension][dimension];
main.c
#include "common.h"
You have a definition of the array variable in the header file. If you include it in more than one file you will have duplicate (or multiple) definitions of the same global variable which will be reported as an error by the linker.
In the header file you should have a declaration only like
extern unsigned int board[dimension][dimension];
and a definition in exactly one C file at file scope, i.e. not in a function. For example you can use this definition in main.c
unsigned int board[dimension][dimension];
It must be this way if you want to access the variable from more than one .c file.
To put this variable on the stack it must be inside a function, e.g. in main(), but this way you cannot use it as a global variable. You could use a pointer variable as a global variable and initialize this in main() with the address of the array. This has the drawback that the functions that use the pointer cannot determine the two array dimensions from the variable itself. Of course they could use the preprocessor symbol.
Example:
common.h
#ifndef COMMON_H
#define COMMON_H
#define dimension 5
extern unsigned int (*board)[dimension];
#endif // COMMON_H
main.c
#include "common.h"
#include "other.h"
unsigned int (*board)[dimension];
int main(void)
{
unsigned int the_board[dimension][dimension] = {{ 0 }};
board = the_board;
printf("board[1][2] = %d\n", board[1][2]);
some_function();
printf("board[1][2] = %d\n", board[1][2]);
return 0;
}
other.h
#ifndef OTHER_H
#define OTHER_H
void some_function(void);
#endif // OTHER_H
other.c
#include "common.h"
#include "other.h"
void some_function(void)
{
board[1][2] = 3;
}
If you want to have the variable at a specific address or in a specific address range (but not on the stack) you could use a (linker specific) linker script to define a memory section at a specific address range and use a (compiler specific) #pragma section("name") or __attribute__((section("name"))) to put a normal global variable into this memory section.
So I'm working through this chapter of a sweet modern OpenGL tutorial, and in part of the code I assign a void pointer variable to the return value of a void * function from a second file. I got this error from gcc: initialization makes pointer from integer without a cast. As a test, I tried merging the two files and compiling again. This time, with the function in the same file as where it's called, I get no error.
I was able to reproduce this with three minimal files:
file1.c
void main() {
void *newval = foo();
}
file2.c
#include <stdlib.h>
void *foo() {
void *val;
val = malloc(10);
return val;
}
file3.c
#include <stdlib.h>
void *foo() {
void *val;
val = malloc(10);
return val;
}
void main() {
void *newval = foo();
}
file3.c is just the first two combined. My question is why when I compile one way I get an error, and the other way I get none:
$gcc file1.c file2.cfile1.c: In function ‘main’: file1.c:2:17:
warning: initialization makes pointer from integer without a cast
[enabled by default]$gcc file3.c$
I thought that the file1.c + file2.c combo was identical to file3.c. What am I missing?
In your file1.c, it seems the declaration of void *foo() is missing.
You can either include the header file containing this declaration or add line void *foo() on top of file1.c.
When compiler finds symbol foo followed by ( in main file, and there was no declaration, it assumes foo accepts any number of arguments and returns an int. So you see the warning that int is being converted to a pointer.
But in file file3.c, symbol foo is known as it is a defined function before its first usage so compiler knows that foo returns a pointer and thus no warning.
You need to declare the foo() function so that compiler knows what it is when it compiles file1.c.
Create file2.h and add in it
void *foo();
add include it in file.c
#include "file2.h"
Without declaration, the compiler assumes all unknown functions as returning int, but as your function returns void * and you are assigning it to void *, its trying to assign int to void * and hence you are getting that warning.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I share variables between different .c files?
If I have two source files, and one header: file1.c, file2.c, and header.h, and:
--header.h--
int i;
--file1.c--
#include <header.h>
i = 10;
int main() {
func();
return 0;
}
--file2.c--
#include <header.h>
void func() {
printf("i = %d\n", i);
return;
}
I get the warning that i defaults to an int. What could I do if I want to have i as a float for instance?
Make it
extern int i;
in the header and
int i = 10;
in file1.c.
The warning means that for the (incomplete) declaration i = 10; in file1.c, the "implicit int" rule is applied, in particular, that line is interpreted as a declaration (since an assignment cannot appear outside function scope).
You have a couple of errors in your code. The first is that you define the variable i in the header file, which means that it will be defined in all source files that include the header. Instead you should declare the variable as extern:
extern int i;
The other problem is that you can't just assign to variables in the global scope in file1.c. Instead it's there that you should define the variable:
int i = 10;
Declare it as extern in the header (this means memory for it is reserved somewhere else):
/* header.h */
extern int i;
Then define it in only one .c file, i.e. actually reserve memory for it:
/* file1.c */
int i = <initial value>;
In the header use
extern int i;
in either file1.c or file2.c have
int i = 20;
If you want float just change int to float
In 99.9% of all cases it is bad program design to share non-constant, global variables between files. There are very few cases when you actually need to do this: they are so rare that I cannot come up with any valid cases. Declarations of hardware registers perhaps.
In most of the cases, you should either use (possibly inlined) setter/getter functions ("public"), static variables at file scope ("private"), or incomplete type implementations ("private") instead.
In those few rare cases when you need to share a variable between files, do like this:
// file.h
extern int my_var;
// file.c
#include "file.h"
int my_var = something;
// main.c
#include "file.h"
use(my_var);
Never put any form of variable definition in a h-file.
I have a RefTables.pc file.
When I execute the make command, I get this warning:
RefTables.c:109: warning: type defaults to `int' in declaration of `sqlcxt'
RefTables.c:111: warning: type defaults to `int' in declaration of `sqlcx2t'
RefTables.c:113: warning: type defaults to `int' in declaration of `sqlbuft'
RefTables.c:114: warning: type defaults to `int' in declaration of `sqlgs2t'
RefTables.c:115: warning: type defaults to `int' in declaration of `sqlorat'
How can I remove it?
I am using linux & gcc compiler.
It's been a while since I used Pro*C, but I think you can add a command line option to the proc command line
code=ANSI_C
which will give prototypes for the functions named.
You can remove the warning by specifying the type of the 5 offending declarations. Actually, they must be declared with no type at all, which defaults to int in C (but generates a warning).
Edit: I found on Google this declaration.
extern sqlcxt (/*_ void **, unsigned int *, struct sqlexd *, struct sqlcxp * _*/);
The function has no return type. It should have one. Write it as follows.
extern int sqlcxt (/*_ void **, unsigned int *, struct sqlexd *, struct sqlcxp * _*/);
Or you can manually state in the compiler command line to ignore these warnings. They won't be displayed anymore.
In the future, provide a code snippet along with the warnings so that we have some context to work from. Otherwise we can only guess at what the real problem is.
I'm assuming that sqlcxt, sqlcx2t, etc., are functions. Without seeing the source code, it sounds like you don't have a declaration for those functions in scope before using them.
Here's a short example of what I mean:
int main(void)
{
foo();
return 0;
}
void foo(void)
{
// do something interesting
}
When the compiler sees the call to foo in main, it doesn't have a declaration in scope, so it assumes that foo returns int, not void, and will return a warning similar to what you got above.
If your functions are defined in the same file as they are called, there are two ways around this problem. My preferred way is to define the function before it is used:
void foo(void)
{
// do something interesting
}
int main(void)
{
foo();
return 0;
}
Another way is to have a declaration of the function in scope before calling it:
void foo(void);
int main(void)
{
foo();
return 0;
}
void foo(void)
{
// do something interesting
}
It sounds like these functions are part of a database API; if so, there should be a header file that contains declarations for those functions, and that header should be included in your source file:
/** foo.c */
#include "foo.h"
void foo(void)
{
// do something interesting
}
/** end foo.c */
/** foo.h */
#ifndef FOO_H
#define FOO_H
void foo(void);
#endif
/** end foo.h */
/** main.c */
#include "foo.h"
int main(void)
{
foo();
return 0;
}
/** end main.c */
Hope that helps.