2D array of strings in C - c

I'm making an application in C that will use text menus. So, I decided to create a global array containing all the menus. As a workaround of an issue I will mention later, the code looks like this:
char* main_menu[]=
{"Refresh rate", "Help", "Default config", NULL};
char* other_stuff[]=
{"Stuff", "More", NULL};
char** screens[]={main_menu, other_stuff};
And I can use those strings like: screens[0][1] meaning first (or rather second, since we count from zero) option in zeroth/first menu.
It works, but it strikes me as quite inelegant that I had to declare those auxilliary arrays (main_menu and other_stuff). I tried to make use of nested brace initialization of arrays, but always the compiler would complain. Also, before you suggest declaring the array as, say, char* screeens[10][5] - there should be no magic numbers, as this is equally inelegant for me.
I tried:
char** screens[]={
{"Refresh rate", "Help", "Default config", NULL},
{"Stuff", "More", NULL}
};
However, the compiler gives me a warning (and rightfully, as accessing elements yields gibberish):
../main.c:96:1: warning: braces around scalar initializer [enabled by default]
{"Refresh rate", "Help", "Default config", NULL},
^
../main.c:96:1: warning: (near initialization for ‘screens[0]’) [enabled by default]
../main.c:96:1: warning: initialization from incompatible pointer type [enabled by default]
../main.c:96:1: warning: (near initialization for ‘screens[0]’) [enabled by default]
../main.c:96:1: warning: excess elements in scalar initializer [enabled by default]
and so on.
If I change the first line to char* screens[][]={, the compiler won't compile the code at all, giving error: error: array type has incomplete element type.
I'm writing in embedded evironment (avr-gcc 4.8.1), where memory is quite scarce, so I don't want to declare arrays bigger than necessary, thus wasting memory. Is there anything I can do, or is this as simple as possible?

Assuming you have C99 or later, you can use 'compound literals' to initialize your array:
#include <stddef.h> // NULL
char **screens2[] =
{
(char *[]){ "Refresh rate", "Help", "Default config", NULL },
(char *[]){ "Stuff", "More", NULL },
};
Or, if you want to be const-correct (a good thing — thanks to M.M and his comment):
char const * const * screens3[] =
{
(char const * const []){ "Refresh rate", "Help", "Default config", NULL },
(char const * const []){ "Stuff", "More", NULL },
};
Compilation (clean — no warnings or errors):
gcc -std=c11 -O3 -g -Wall -Wextra -Werror -pedantic -c 2das.c
(GCC 5.1.0 on Mac OS X 10.10.5)

I'm making an application in C that will use text menus.
You could try something like this:
#include <stdio.h>
#include<unistd.h>
typedef int (*menu)(void);
void clearScreen(int x){
int i=0;
for(;i<x;i++){
printf("\n");
}
}
int exitMenu(void) {
clearScreen(100);
printf("Exiting... Goodbye\n");
sleep(1);
return 0;
}
int mainMenu(void){
clearScreen(100);
printf("\t\t\tMain Manu\n");
return 0;
}
int updateSystem(void) {
clearScreen(100);
printf("System update...\n");
sleep(1);
return 1;
}
int installVlcFromPpa(void) {
clearScreen(100);
printf("Install VLC from PPA \n");
sleep(1);
return 0;
}
int installVlcFromSource(void) {
clearScreen(100);
printf("Install VLC from Source \n");
sleep(1);
return 0;
}
int uninstallVLC(void) {
clearScreen(100);
printf("Uninstall VLC... \n");
sleep(1);
return 1;
}
int chooseOption(int min, int max){
int option,check;
char c;
do{
printf("Choose an Option:\t");
if(scanf("%d%c",&option,&c) == 0 || c != '\n'){
while((check = getchar()) != 0 && check != '\n');
printf("\tThe option has to be between %d and %d\n\n",min,max);
}else if(option < min || option > max){
printf("\tThe option has to be between %d and %d\n\n",min,max);
}else{
break;
}
}while(1);
return option;
}
void showMenu(char *question, char **options, menu *actions, int length) {
int choose = 0;
int repeat = 1;
int i;
menu act;
do {
printf("\n\t %s \n", question);
for(i = 0; i < length; i++) {
printf("%d. %s\n", (i+1), options[i]);
}
choose = chooseOption(1,length);
printf(" \n");
act = actions[choose - 1];
repeat = act();
if(choose == 3){
repeat = 0;
}
}while(repeat == 1);
}
int installVLC(void) {
clearScreen(100);
char *question = "Installing VLC from:";
char *options[10] = {"PPA", "Source", "Back to VLC menu"};
menu actions[3] = {installVlcFromPpa, installVlcFromSource, mainMenu};
showMenu(question, options, actions, 3);
return 1;
}
int meniuVLC(void) {
clearScreen(100);
char *question = "VLC Options";
char *options[10] = {"Install VLC.", "Uninstall VLC.", "Back to Menu."};
menu actions[3] = {installVLC, uninstallVLC, mainMenu};
showMenu(question, options, actions, 3);
return 1;
}
void startMenu(void){
clearScreen(100);
char *question = "Choose a Menu:";
char *options[10] = {"Update system.", "Install VLC", "Quit"};
menu actions[3] = {updateSystem, meniuVLC, exitMenu};
showMenu(question, options, actions, 3);
}
int main(void){
startMenu();
return 0;
}
Choose a Menu:
1. Update system.
2. Install VLC
3. Quit
Choose an Option:

The most elegant way is to declare them as separate variables.
You can also use the first method but utilizing enums/defines, so that you have screens[MAIN_MENU][...] rather that some magic screens[0xcafebabe][...], it is equally acceptable.

Related

How would I get this code to be executed without using stdlib.h

I keep receiving an error regarding malloc and I'm trying to find out how to get this code to work without using stdlib.h in the header. Just stdio.h, is this possible and how? As I'm totally confused
#include <stdio.h>
void allocate(int* score_array, const int input)
{
int iter;
for(iter = 1;iter <= 11;++iter)
{
if( (input < iter*10) && (input >= (iter-1)*10 ) )
{
++(score_array[iter-1]);
}
}
}
void printf_star(const int len)
{
int iter;
for(iter = 0;iter < len;++iter)
{
printf("*");
}
printf("\n");
}
int main()
{
int iter, size, temp;
int* buffer;
int score_array[11];
for(iter = 0;iter < 11;++iter)
{
score_array[iter] = 0;
}
printf("How many grades will you be entering?\n");
printf("Enter a number between 1 and 100: ");
scanf("%d", &size);
buffer = (int*)malloc(size*sizeof(int));
for(iter = 1;iter <= size;++iter )
{
printf("Getting grade %d. You have %d grade(s) left to enter\n", iter, size-iter+1);
printf("Enter a number between 0 and 100: ");
scanf("%d",&temp);
if( (temp>=0) && (temp <= 100) )
{
buffer[iter-1] = temp;
}
else
{
do
{
printf("Invalid Value!\n");
printf("Getting grade %d. You have %d grade(s) left to enter\n", iter, size-iter+1);
printf("Enter a number between 0 and 100: ");
scanf("%d",&temp);
}
while( (temp < 0) || (temp > 100) );
}
}
for(iter = 1;iter <= size;++iter)
{
allocate(score_array, buffer[iter-1]);
}
for(iter = 0;iter < 11;++iter)
{
printf_star(score_array[iter]);
}
return 0;
}
I keep getting this error:
hw08.c: In function ‘main’:
hw08.c:56: warning: incompatible implicit declaration of built-in function ‘malloc’
This is only a warning, not an actual error, so the program still compiles.
To eliminate the warning you can declare the malloc in your file:
#include <stdio.h>
extern void * malloc(unsigned long);
You could also just include stdlib.h, unless you have a major reason not to.
Header files just define the functions prototypes by using the extern keyword. The actual implementation of malloc resides in libc depending on the OS.
Not defining a function/system call prototype is indeed a warning, not a compile-time error, contrary to what many have conveyed in the comments!
Coming to the actual workaround, if you want to avoid using the #include <stdlib.h>, you either need to use:
#include <malloc.h> (deprecated since c89)
Define the header all by yourself, with extern void * malloc(size_t);
Credits to #Chris Rouffer too! :)
You need to include stdlib.h if you want to access the malloc() function, because that is where it is defined. Otherwise the compiler doesn't know what to do.
You really are supposed to include the header in your code if you want to use the function, however, in theory you could just paste the implementation of malloc() in your source and then use it from there without the header. This is a bad idea however, since anybody looking at the code would expect malloc() to refer to the standard implementation defined in stdlib.h.

Warning: type of ‘numRest’ defaults to ‘int’ (in function 'sleep')

I get a warning In function ‘sleep’: warning: type of ‘numRest’ defaults to ‘int’ and I have no idea why. It runs perfectly fine but apparently I got this warning. Does anyone else get this warning when they run it?
void sleep(numRest){
if ((numRest >= 0) && (numRest <=4)){
printf("Sleep deprived!");
}
else if ((numRest > 4) && (numRest < 6)){
printf("You need more sleep.");
}
else if ((numRest >= 6) && (numRest < 8)){
printf("Not quite enough.");
}
else{
printf("Well done!");
}
return;
}
int main()
{
int numSleep = -1;
if (numSleep == -1){
printf("Test 1\n");
printf("Input: -1\n");
printf("Expected Result: Error, you cannot have a negative number of hours of sleep.\n");
printf("Actual Result: ");
sleep(numSleep);
printf("\n\n");
numSleep = 4.5;
printf("Test 2\n");
printf("Input: 4.5\n");
printf("Expected Result: You need more sleep.\n");
printf("Actual Result: ");
sleep(numSleep);
printf("\n\n");
}
return 0;
}
The issue is with the function signature definition.
void sleep(numRest) {
should be
void sleep(int numRest) {
Otherwise, the compiler will "assume" (now obsolete by latest standard) that the missing datatype is int.
Related, quoting from C11, Major changes (over previous versions) list
remove implicit int
That said,
sleep() is a library function already, prototyped in unistd.h, do not try to use the same for for user-defined functions.
int main() should be int main(void), at least for hosted environments to conform to the standard.
You have to explicitly put variable type in function declaration as:
void sleep(int numRest) {
//your code here
}

How to solve the error "assignment makes integer from pointer without a cast"?

Here is the piece of code: I wonder where my mistake is?
I have a structure named country, working with linked lists, and here is my function for searching:
country *search(char *v)
{
country *c; c=head;
while(c)
{
if(strcmp(c->name,v)==0)
{return c;}
c=c->next;
if(c==head) break;}
return (void *)-1;}
In main I have (k is a int variable):
printf(" \n\tEnter name of country for searching: ");
fflush(stdin); gets(v);
k = search(v); // Function for searching
if(k>=0)
{puts("\n\t Info about Country: \n ");
When I compile this in Dev C++, I get:
[Warning] assignment makes integer from pointer without a cast [enabled by default]
How do I fix this problem?
Couple of things to fix:
The return value of search when you don't find what you are searching for:
country *search(char *v)
{
country *c; c=head;
while(c)
{
if(strcmp(c->name,v)==0)
{
return c;
}
c=c->next;
if(c==head) break;
}
// Don't use -1 as an invalid search.
// Use NULL instead.
// return (void *)-1;
return NULL;
}
Use the right variable type to assign the return value of search.
// Don't use k, which is of type int.
// Use a variable of the right type.
// k = search(v);
country* cPtr = search(v);
if( cPtr )
{
puts("\n\t Info about Country: \n ");
}

Implementing AI pointer error

For my uni project I'm trying to create a basic tank game in C, but I've only just started learning C and have a very basic understanding of C. So I've started working on some simple code for a AI player, but when I compile it with GNU GCC compiler it comes up with these errors and I've got no clue how to proceed. So help would be great please! :D
Line 41 warning: passing argument 3 of 'AIMove' makes pointer from integer without a cast [enabled by default]
Line 19 note: expected 'int (*)()' but argument is of type 'int'
int PosCheck(int T1Pos, int T2Pos)
{
int a;
a = T2Pos - T1Pos;
if(a == 0) // Stop the tanks trying to overlay
{
return 0;
}
if(a >= 1 || a < 0) // Allows the tanks to move foward
{
return 1;
}
}
int AIMove(int T1Pos, int T2Pos, int PosCheck()) // AI movement
{
int b, c;
if(PosCheck(T1Pos, T2Pos) == 0) // Choose retreat options or stands still
{
b = 3 + round(3*(int)rand()/(int)RAND_MAX);
return b;
}
if(PosCheck(T1Pos, T2Pos) == 1) // Chooses foward options
{
c = 1 + round(3*(int)rand()/(int)RAND_MAX);;
return c;
}
}
main()
{
int T1Pos;
int T2Pos;
int T2MC;
T2MC = AIMove(T1Pos, T2Pos, PosCheck(T1Pos, T2Pos));
}
This function takes another function as a parameter because of these parens:
int AIMove(int T1Pos, int T2Pos, int PosCheck()) // AI movement
^^
But when you call it, you are passing the result of a same-named function:
T2MC = AIMove(T1Pos, T2Pos, PosCheck(T1Pos, T2Pos));
What is the PosCheck parameter supposed to do? Inside AIMove you call it, but it's not clear if you want the global PosCheck function or the argument.
By the way, the usual way to declare a function pointer is with an asterisk:
int AIMove(int T1Pos, int T2Pos, int (*PosCheck)()) // Obviously a pointer.
If there's nothing in particular you are trying to accomplish there, just delete the parameter and the argument.
T2MC = AIMove(T1Pos, T2Pos);
int AIMove(int T1Pos, int T2Pos)

Implicit declaration of functions

I am getting this error from the isdigit and isalpha functions
warning: implicit declaration of function ‘isdigit’ [-Wimplicit-function-declaration]
numberCheck = isdigit(englishWords[i]);
warning: implicit declaration of function ‘isalpha’ [-Wimplicit-function-declaration]
letterCheck = isalpha(englishWords[i]);
my code is:
char * inputEnglish()
{
char englishWords[MAX_LENGTH];
char required[MAX_LENGTH] = {"message="};
char * messageToBeSent;
int i;
int numberCheck;
int letterCheck;
i = 0;
printf("Please enter the word you'd like to translate\n");
fgets(englishWords, MAX_LENGTH, stdin);
for(i = 0; i < (strlen(englishWords) + 1); i++)
{
numberCheck = isdigit(englishWords[i]);
letterCheck = isalpha(englishWords[i]);
if((numberCheck != 0) || (letterCheck != 0))
{
printf("Please enter valid Input");
}
}
strcat(required, englishWords);
messageToBeSent = malloc(sizeof(char)*(strlen(required)+1));
strcpy(messageToBeSent, required);
return (messageToBeSent);
}
How do i get rid of these warnings?
You're using functions that the compiler has not been informed about, so it makes assumptions, in particular about the return type. As #ShafikYaghmour says in the comments, the proper include file will provide the compiler with the necessary information, even though (in this case) your code will probably work.

Resources