I have several years of experience with java, but I'm very new to C. I'm still struggling to figure out when and when not to use pointers. I was given this base code and need to finish the 'push' method so that it pushes the next element onto the stack, but I'm getting errors saying:
request for member 'top' in something not a structure.
#include <assert.h>
#include <libgen.h>
#include <stdio.h>
#include <stdlib.h>
int exit_status = EXIT_SUCCESS;
#define EMPTY (-1)
#define SIZE 16
typedef struct stack stack;
struct stack {
int top;
double numbers[SIZE];
};
void push (stack *the_stack, double number) {
if(&&the_stack.top>=SIZE-1){
printf("error");
}else{
the_stack.numbers[&&the_stack.top++ ] = number;
}
}
int main (int argc, char **argv) {
if (argc != 1) {
fprintf (stderr, "Usage: %s\n", basename (argv[0]));
fflush (NULL);
exit (EXIT_FAILURE);
}
stack the_stack;
the_stack.top = EMPTY;
char buffer[1024];
for (;;) {
int scanrc = scanf ("%1023s", buffer);
if (scanrc == EOF) break;
assert (scanrc == 1);
if (buffer[0] == '#') {
scanrc = scanf ("%1023[^\n]", buffer);
continue;
}
char *endptr;
double number = strtod (buffer, &endptr);
if (*endptr == '\0') {
push (&the_stack, number);
}else if (buffer[1] != '\0') {
bad_operator (buffer);
}else {
do_operator (&the_stack, buffer);
}
}
return exit_status;
}
Am I overlooking something very basic?
When accessing members of a structure, there are two operators: The dot operator . which is used for non-pointer structures, and the "arrow" operator -> which is used for pointers to structures.
You have a pointer to a structure in your push function, so you need to use the "arrow" operator.
There are other problems with your code, like the double ampersand in the push function. You also don't need to flush any files when exiting the program, the runtime will do that for you.
It seems very clearly that you have less experience in C. There are lots of compile time errors in your code like for example :
In push function top and numbers should be invoked as :
the_stack->top
the_stack->numbers[]
An arrow is used to invoke the members of a pointer variable.
Now Comparing it with Java:
Java uses only references not pointers. But internally they are pointing to some location in memory.
https://www.dropbox.com/s/qfk86yb3drdlmz2/C%20to%20Java.JPG Image
http://erikdemaine.org/papers/CPE98/paper.pdf Paper
Check this link to correlate C code and Java code.
Related
Now I have an input consists of a random string with '(' and ')'. I want to push these parentheses into a stack called "balance". But after I input, the program would terminate, and there was nothing in the stack. How can I fix this?
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#define STACKSIZE 1000
struct stack
{
int top;
char items[STACKSIZE];
};
void push(struct stack *pb, char x)
{
if(pb->top==STACKSIZE)
printf("The stack is full\n");
else
pb->items[pb->top++]=x;
}
int main()
{
while(1)
{
struct stack balance; //the stack called "balance"
struct stack *b; //the pointer of stack
char line[STACKSIZE]; //input
scanf("%s", line);
if(!strcmp(line, "-1")) //program stops when only "-1"
break;
b->top=0; //initializing top value
for(int i=0;i<STACKSIZE-1;i++)
{
if(line[i]=='(' || line[i]==')') //push '(' and ')' in the input to the stack
push(b, line[i]);
}
printf("test"); //can't reach this line
printf("%s\n", b->items);
}
return 0;
}
For some reason, you're using b as a pointer to the stack, instead of &balance itself. This is not wrong, but you must initialize b so it really points to the struct. So, instead of:
struct stack *b;
You should have:
struct stack *b = &balance;
Another potential problem is that you're reading until i reaches STACKSIZE. This is wrong, since you don't know whether the input is going to reach that length, and if it does not, then you're reading ahead of the end of line.
So, instead of:
for(int i=0;i<STACKSIZE-1;i++)
{
You should have:
for(int i=0;line[i] != '\0';i++)
{
BTW, you don't need to define ("redefine for each iteration"), all your locals inside the loop. That's is actually not going to happen, since the optimizer will move them out, but anyway.
Talking of potential problems, it is always a bad idea to have and infinite loop. Define exactly what is the exit condition, and you'll be in the safe side. You can even define something exceptional to happen and call break in that case, but not as the common rule.
You're reading input, and in this case something really common is the read-ahead technique.
int input_status = scanf("%s", line);
while(input_status != EOF
&& strcmp(line, "-1"))
{
// more things...
input_status = scanf("%s", line);
}
This way, each time you're testing the exit condition, you've just read and check whether the end condition ("-1" at input) or there is simply not more input (scanf returns EOF).
Here comes the complete code:
#include <stdio.h>
#include <stdlib.h>
#define STACKSIZE 1000
struct stack
{
int top;
char items[STACKSIZE];
};
void push(struct stack *pb, char x)
{
if(pb->top==STACKSIZE)
printf("The stack is full\n");
else
pb->items[pb->top++]=x;
}
int main()
{
struct stack balance; //the stack called "balance"
struct stack *b = &balance; //the pointer of stack
char line[STACKSIZE]; //input
int input_status = scanf("%s", line);
while(input_status != EOF
&& strcmp(line, "-1"))
{
b->top=0; //initializing top value
for(int i=0;line[i] != '\0';i++)
{
if(line[i]=='(' || line[i]==')') //push '(' and ')' in the input to the stack
push(b, line[i]);
}
printf("test"); //can't reach this line
printf("%s\n", b->items);
input_status = scanf("%s", line);
}
return 0;
}
I am learning stacks right now and I decided to try to make a little program involving the stack from Magic the Gathering rules, which also follows a LIFO order.
The user asked whether they would like to
play a spell (push)
resolve a spell (pop) or
exit.
Now the tricky part is that I am trying to allow the elements of the stack to be multiple words each. This has been causing A LOT of problems.
I can input a word and print it outside the while(1) loop but if I put it inside everything goes haywire. Any ideas?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100
typedef struct {
char item[SIZE];
int top;
} stack;
void init(stack*);
void push(stack*, char[]);
char pop(stack*);
void init(stack* st) {
st->top = -1;
}
void push(stack* st, char* value) {
if (st->top == SIZE - 1) {
printf("STACK OVERFLOW\n");
return;
}
st->top++;
strcpy(st->item[st->top], value);
}
char pop(stack* st) {
if (st->top == -1) {
printf("STACK UNDERFLOW\n");
return -1;
}
char value;
strcpy(value, st->item[st->top]);
st->top--;
return value;
}
int main() {
stack st1, st2;
int choice;
char val[20];
init(&st1);
init(&st2);
printf("You have priority. What would you like to do?\n\n");
printf("1. Cast a spell\n2. Resolve the next spell\n3. Pass priority\n\n");
while (1) {
scanf("%d", &choice);
switch (choice) {
case 1:
printf("What is the spell?\n\n");
scanf("%[^\n]s", val);
printf("%s", val);
push(&st1, val);
case 2:
strcpy(val, pop(&st1));
printf("%s resolves.\n\n", val);
case 3:
exit(0);
}
}
return 0;
}
The reason you would be getting errors is that because of the type conversions.
char pop(stack* st) {
if (st->top == -1) {
printf("STACK UNDERFLOW\n");
return -1;
}
char value;
strcpy(value, st->item[st->top]);
st->top--;
return value;
}
The first thing, you don't need to pass the address when dealing with the arrays. The another thing is that you are trying to copy a whole string into a single character variable. So, there are so much type conversion problems in your code.
I suggest you to make the functions of void data type and provide the functionality within the block of the function. Just call the pop function with top value as an argument, and print the string within the function that you are popping.
Stack is a zero order data structure so it doesn't require inputs for popping purpose.
I'm very new to C and having trouble returned a pointer to a two dimensional array.
The purpose of the code is to go into a folder called rules. From this folder it finds all the file paths for all the files in the rule folder. I want to populate the a two dimensional array with the complete file paths. As of now my code is capable of populating a two dimensional array with the the filepaths (this is done in the listFiles Method). I would like to use this two dimensional array within the main method, to do some further stuff. But I am having issues trying to get it to return, without causing compiling issues.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
#include <string.h>
void listFiles(char *path);
int main() {
// Directory path to list files
char path[100];
char buff[FILENAME_MAX];
GetCurrentDir(buff, FILENAME_MAX);
// printf("%s\n",buff);
char toRuleFolder[100] = "/rules";
strcat(buff, toRuleFolder);
// printf("%s\n",buff);
listFiles(buff);
return 0;
}
void listFiles(char *path) {
char pathToUse[100];
struct dirent *dp;
char *arrayOfArraysOfChars[30][50]; // array to hold multiple single
// arrays of characters
DIR *dir = opendir(path);
printf(" %s\n", path);
return;
char *token;
const char s[2] = "-";
int counter = 0;
char pathToSave[100];
while ((dp = readdir(dir)) != NULL) {
token = strtok(dp->d_name, "");
while (token != NULL) {
if (strcmp(token, ".") != 0) {
if (strcmp(token, "..") != 0) {
strcpy(pathToSave, "");
strcpy(pathToSave, path);
strcat(pathToSave, "/");
strcat(pathToSave, token);
strcpy(arrayOfArraysOfChars[counter], pathToSave);
counter += 1;
}
}
token = strtok(NULL, s);
}
}
printf("%s\n", "sdasdasdssad");
printf("%s\n", arrayOfArraysOfChars[0]);
printf("%s\n", arrayOfArraysOfChars[1]);
printf("%s\n", arrayOfArraysOfChars[2]);
printf("%s\n", arrayOfArraysOfChars[3]);
closedir(dir);
}
arrayOfArraysOfChars is populated with the information I need. But I would like to be able to access this array from the main function. How would I do this?
I am assuming your compiler is warning you about returning local variables.
char *arrayOfArraysOfChars[30][50]
The memory used by this variable will be reused for the next stack frame when the function is finished, overwriting it and making it useless.
a) Pass it in as a parameter
b) Make it static (yuk)
c) Dynamically allocate it and return the pointer
Also, consider using a linked list of allocated strings rather than an array as I guess you don't know for sure how many files you're going to find or how long their names are.
I have some troubles when using strcpy to copy an array of string inside a double pointer with allocated memory, but i can't understand why i get segmentation fault even if i have previously allocated memory.
Here is the code:
#include <stdio.h>
#include <string.h>
typedef struct Students {
int q_exams;
char **done_exams;
}Students;
int main() {
Students a;
int i;
char support[30];
printf("how many exams have you done ?\n");
scanf("%d",&(a.q_exams));
a.done_exams=malloc(sizeof(char*)*a.q_exams);
if(a.done_exams==NULL)
{
printf("out of memory\n");
return 0;
}
for(i=0;i<a.q_exams;i++)
{
printf("Insert the name of the exam\n");
scanf("%28s",support);
a.done_exams[i]=malloc(strlen(support)+1);
if(a.done_exams[i]==NULL)
{
printf("out of memory\n");
return 0;
}
strcpy(a.done_exams[i][0],support);
fflush(stdin);
}
return 0;
}
You need to pass an address of the initial character to strcpy, either like this
strcpy(&a.done_exams[i][0],support);
// ^
// Add an ampersand
or equivalently like this:
strcpy(a.done_exams[i] , support);
// ^
// Remove the second index
Currently, your code passes the value* of the initial character, rather than its address.
* The value is undefined at the time as well, but it is not the primary cause, because you should not be passing value at all.
This code is fixed
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct Students {
int q_exams;
char **done_exams;
} Students;
int main()
{
Students a;
int i;
char support[49];
printf("how many exams have you done ?\n");
scanf("%d",&(a.q_exams));
a.done_exams = malloc(sizeof(char*) * a.q_exams);
if(a.done_exams==NULL)
{
printf("out of memory\n");
return 0;
}
for(i = 0 ; i < a.q_exams ; i++)
{
printf("Insert the name of the exam\n");
scanf("%48s",support);
a.done_exams[i] = malloc(strlen(support)+1);
if(a.done_exams[i] == NULL)
{
printf("out of memory\n");
return 0;
}
strcpy(a.done_exams[i]/*[0]*/, support);
/* ^ ^- this is wrong
* + pass the address to the array not the first element value
*
* if you had warnings turned on you would have seen this
*/
fflush(stdin);
}
return 0;
}
notice that
scanf("%48s", support);
requires
char support[49];
which is also fixed in the code.
See the man page of strcpy().
The first argument should be of type char *.
As per your code, the argument [a.done_exams[i][0]] is of type char. You need to pass a char * [starting address of the destination] actually.
Change your code to
strcpy(a.done_exams[i],support);
The
strcpy(a.done_exams[i][0],support);
should be
strcpy(a.done_exams[i],support);
or
strcpy(&a.done_exams[i][0],support);
My advice would be to always compile with compiler warnings turned on. My compiler (gcc) does a very good job of catching the problem and telling you exactly what needs to be done to fix it:
test.c:37:12: warning: incompatible integer to pointer conversion passing 'char' to
parameter of type 'char *'; take the address with & [-Wint-conversion]
strcpy(a.done_exams[i][0],support);
^~~~~~~~~~~~~~~~~~
&
P.S. You are also missing some #includes:
#include <stdlib.h>
#include <string.h>
/* This Program generates a file with a pseudo-random number of st_record_t structures. The file is passed by command line arguments. The program must by executed, in UNIX, this way: ./file_gen -path <path> */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "types.h"
#define MSG_INVALID_INPUT "Your input was not valid"
#define CMD_FLAG_PATH_POSITION 1
#define CMD_ARG_PATH_POSITION 2
#define CMD_FLAG_PATH "-path"
#define SDM_MAX 10000.0
status_t validate_arguments (int argc, char * argv []);
int main (int argc, char * argv [])
{
FILE * fi;
size_t i;
st_record_t aux_struct, aux2_struct;
int size;
if ((validate_arguments(argc, argv))!= OK)
{
fprintf(stderr, "%s\n", MSG_INVALID_INPUT);
return EXIT_FAILURE;
}
if((fi = fopen(argv[CMD_ARG_PATH_POSITION], "wb")) == NULL)
return EXIT_FAILURE;
srand(time(NULL));
for (i=0; i<(size=100); i++)
{
aux_struct.SDM = (((float)rand()/(float)(RAND_MAX)) * SDM_MAX); /*pseudo-random real number between 0 and SDM_MAX*/
(aux_struct.ID) = i;
(aux_struct.coordinates)->latitude.deg = rand()%180;
(aux_struct.coordinates)->latitude.min = rand()%60;
(aux_struct.coordinates)->latitude.sec = rand()%60;
(aux_struct.coordinates)->longitude.deg = rand()%180;
(aux_struct.coordinates)->longitude.min = rand()%60;
(aux_struct.coordinates)->longitude.sec = rand()%60;
if((fwrite (&aux_struct, sizeof(st_record_t), 1, fi))!=1)
return ERROR_WRITING_FILE;
}
if(fclose(fi) == EOF)
return EXIT_FAILURE
return EXIT_SUCCESS;
}
The problem is with the (aux_struct.coordinates)->latitude.deg = rand()%180 lines. If instead of using a random number I select one, this won't happen
The st_record_t struct is defined this way:
typedef struct {
unsigned char deg, min, sec;
}angle_t;
typedef struct {
angle_t latitude, longitude;
}st_coord_t;
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
The segmentation fault has nothing to do with random number, it's because you never allocate memory for aux_struct.coordinates.
To fix the problem, use something like:
aux_struct.coordinates = malloc(sizeof(st_coord_t));
Remember to free the memory when it's not used any more.
In addition to the issue of the missing initialization of the "coordinates" member, it should be pointed out that the fwrite() will not do what you want. It will just write the contents of the st_record_t. The value of the pointer "coordinates" has no meaning outside the process that is doing the writing and the data in the st_coord_t structure it points to will not get written at all.
You might want to look at something like hdf5 to write complex binary data structures to file in a portable way.
You have
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
As you can see,coordinates is a pointer of type st_coord_t. You need to allocate memory for it using malloc:
aux_struct.coordinates=malloc(sizeof(st_coord_t));
And you need to free the allocated memory after its use using:
free(aux_struct.coordinates);
Note that you must allocate memory for coordinates in aux2_struct if you want to use it and later free it after its use.