I am trying to add strings to the stack. Please tell me what's wrong in the program.
In this program, I am trying to implement the stack as a data structure. I know how to add numbers to the stack and / or remove them, but I don't know how to add character input. Right now I want to do something like a list of items and then print the whole list.
//Array implementation of the stack
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 11
char A[MAX_SIZE];
int top = -1;
void Push(char x[])
{
if (top == MAX_SIZE - 1) {
printf("Error! Array size: %d exceeded\n", MAX_SIZE);
return;
}
A[++top] = x;
}
void Pop() {
if (top == -1) {
printf("Error! No element to pop\n");
return;
}
top--;
}
char Top()
{
return A[top];
}
void Print()
{
int i;
printf("Stack: ");
for (i = 0; i <= top; i++)
printf("%s ", A[i]);
printf("\n");
}
int main()
{
char name1[10] = "Pablo";
Push(name1);
char name2[10] = "Robert";
Push(name2);
Print();
}
invalid conversion from 'char' to 'char' [-fpermissive]
16 | A[++top] = x;
| ^
| |
| char*
The elements of the array
char A[MAX_SIZE];
are char, which can store only one character.
On the other hand, the argument x is char* (char x[] has the same meaning as char* x in function arguments). Therefore type mismatch occurs.
Changing the array to
char* A[MAX_SIZE];
and the function Top to
char* Top()
will make your program work.
Note that then the pointers will be directly stored instead of copying strings, so be careful not to dereferenced pointers to vanished object. (This won't be problem in this code)
Your stack A is declared as an array of char, so it can only hold a single string (or an array of characters). In the line in question, you're attempting to assign a char * to a single char.
You should instead define A as an array of char *:
char *A[MAX_SIZE];
Related
I'm writing a code to convert postfix to infix. but when i try to print the stack elements to check it it's not showing any thing. in the push function it prints the top element, but the display function only shows the top element no matter what. and there is segmentation fault after the line strcat(nn,y).The input i tried was 09+.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 20
char *stk[MAX], a[MAX];
int t = -1;
void push(char x[]);
void pop();
void display();
int main()
{
int i = 0;
char *x, *y, nn[MAX];
printf("enter expression:");
gets(a);
while (a[i] != '\0')
{
if (isdigit(a[i]))
{
push((char [2]){ a[i], '\0' });
}
else
{
display();
pop();
x = stk[t];
pop();
y = stk[t];
strcpy(nn, "");
strcat(nn, "(");
strcat(nn, y);
strcat(nn, (char [2]){ a[i], '\0' });
strcat(nn, x);
strcat(nn, ")");
push(nn);
}
i++;
}
printf("%s", stk[0]);
}
void push(char x[])
{
t = t + 1;
stk[t] = x;
printf("curtop %d:%s\n", t, stk[t]);
}
void pop()
{
t = t - 1;
}
void display()
{
printf("%s:%s", stk[t], stk[t - 1]);
}
I will reiterate the comments, with some references, and add a few thoughts of my own.
The first thing you should do is read Why is the gets function so dangerous that it should not be used? gets was removed from language in C11, any halfway modern tool chain should not include it:
example.c:5:9: warning: implicit declaration of function ‘gets’; did you mean ‘fgets’? [-Wimplicit-function-declaration]
fgets is the suggested replacement. Use it.
Both compound literals
(char [2]){ a[i], '\0' }
occur at block scope, and thus have automatic storage duration. This means the lifetime of each object ends when their respective enclosing blocks end.
As such, you are pushing a soon-to-be dangling pointer on to the stack.
This is an example of Undefined Behaviour.
The following
push(nn);
repeatedly pushes the same pointer to the first element of nn on to the stack. This pointer value is always the same, and always points to the current contents of the array, which is constantly being changed.
Both these problems are solved by using dynamic memory to create copies of the strings pushed on to the stack.
nn (infix expression buffer) has the same size as a (postfix expression buffer), with both being much too small.
Remembering that to store a string in a buffer, the size of the buffer must be at least the length of the string plus one (for the null terminating byte).
The postfix expression
09+6+10*+63-/
has a string length of 13, which fits in a. With your parenthesis rules, this creates the infix expression
((((0+9)+6)+(1*0))/(6-3))
which has a string length of 25. This does not fit in nn, and strcat does nothing to guard against buffer overflows.
This would be another example of Undefined Behaviour.
As a quick point of design
pop();
x = stk[t];
is clumsy.
While the use of file scope variables (globals) and functions that wrap around them is a very common way data structures are introduced to beginners, you should still aim to implement something closer to an abstract data type.
pop should return the topmost element of the stack, and you as a user of the pop function should not care how that is managed, just that it behaves as expected.
char *x = pop();
The next step is to remove the file scope variables, so that more than one stack can exist in your programs at the same time.
Here is a cursory example program that addresses most of the issues discussed. Note that it parses input slightly differently, using whitespace as a delimiter. It follows your rules for parenthesis.
It does not validate operands or the resulting expression. Operands can be longer than a single character.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF_SIZE 256
#define SEP " \r\n"
#define STACK_INIT { 0 }
#define STACK_MAX 64
struct stack {
size_t height;
char *data[STACK_MAX];
};
size_t count(struct stack *s)
{
return s->height;
}
int push(struct stack *s, const char *item)
{
if (s->height >= STACK_MAX)
return 0;
char *copy = malloc(1 + strlen(item));
if (!copy)
return 0;
strcpy(copy, item);
s->data[s->height++] = copy;
return 1;
}
char *pop(struct stack *s)
{
return s->height ? s->data[--s->height] : NULL;
}
void free_stack(struct stack *s)
{
char *item;
while ((item = pop(s)))
free(item);
}
int main(void)
{
char buffer[BUF_SIZE];
printf("enter expression: ");
fflush(stdout);
if (!fgets(buffer, sizeof buffer, stdin)) {
if (ferror(stdin))
perror("reading stdin");
return EXIT_FAILURE;
}
struct stack tokens = STACK_INIT;
char *tok = strtok(buffer, SEP);
while (tok) {
char expr[BUF_SIZE * 2];
/* is the first and only character an operator? */
int is_op = strchr("+-/*", *tok) && !tok[1];
if (is_op) {
if (count(&tokens) < 2) {
fprintf(stderr, "Operator (%c) needs two operands.\n", *tok);
free_stack(&tokens);
return EXIT_FAILURE;
}
char *rhs = pop(&tokens);
char *lhs = pop(&tokens);
if (snprintf(expr, sizeof expr, "(%s %c %s)", lhs, *tok, rhs) >= sizeof expr)
fprintf(stderr, "Warning: expression truncated.\n");
free(rhs);
free(lhs);
}
if (!push(&tokens, is_op ? expr : tok)) {
fprintf(stderr, "Failed to push stack item.\n");
free_stack(&tokens);
return EXIT_FAILURE;
}
tok = strtok(NULL, SEP);
}
for (char *s; (s = pop(&tokens)); free(s))
printf("%s\n", s);
}
So, I'm facing an issue that I don't really understand. Please be kind I'm trying to learn C by myself !
I have a function that is called secureInput() that takes a pointer to a string and a size so that, when the user has to type some input I can be sure that there is no buffer overflow. Now, the thing is that I want to modify the string without copying it so instead modifying it directly by it's memory address but it just crashes when the second character in user input is assigned. See comments to see where it crashes.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int secureInput(char **str, int size);
int main(int argc, const char * argv[]) {
char *mystring = NULL; // Declaring it a null so that I use malloc later
secureInput(&mystring, 10);
printf("%s\n", mystring);
}
int secureInput(char **str, int size)
{
*str = (char*)malloc(sizeof(char) *size); // Because **str is a null pointer, I use malloc to allocate memory.
if (*str == NULL)
return -1;
int c = 0;
unsigned int count = 0;
while((c = getchar()) != '\n' && count < size)
/* Here is where it crashes.
* But changing the bellow line as : *str[0][count++] = c;
* works as expected. Also, using a temporary pointer
* and later using it to replace *str, is also working
*/
*str[count++] = c;
*str[count] = '\0';
return 0;
}
So first off, you can pass a string as a char*, no need for char**. That is usually used for an array of strings when passed as argument. Then, if you want to use a fixed size array, a buffer, that has a constant, pre-defined size, don't use malloc. Dynamic memory allocation is always inefficient and risky, so only use it if absolutely necessary.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#define BUFFER_SIZE 10
int secureInput(char *str, int size);
int main(int argc, const char * argv[]) {
char mystring[BUFFER_SIZE]; // Declaring it a null so that I use malloc later
memset(mystring, 0, BUFFER_SIZE);
secureInput(mystring, BUFFER_SIZE);
printf("%s\n", mystring);
}
int secureInput(char *str, int size) {
char c = 0;
unsigned int count = 0;
c = getchar();
while(c != '\n' && count < size - 1) {
str[count++] = c;
c = getchar();
}
str[count] = '\0';
return 0;
}
EDIT:
I can see that there is still some confusion regarding the pointer arithmetic. Here is some address printing and a small figure, I hope it helps:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int secureInput(char **str, int size);
int main(int argc, const char * argv[]) {
char *mystring = NULL; // Declaring it a null so that I use malloc later
secureInput(&mystring, 10);
}
int secureInput(char **str, int size) {
*str = (char*)malloc(sizeof(char) *size); // Because **str is a null pointer, I use malloc to allocate memory.
(*str)[0] = 'a';
(*str)[1] = 'b';
(*str)[2] = 'c';
(*str)[3] = 0;
printf("address of the pointer that points to a pointer that points the first char of the array : %p\n", &str);
printf("value of the pointer that points to a pointer that points to the first char of the array : %p\n", str);
printf("address of the pointer that points to the first char of the array : %p\n", &(*str));
printf("value of the pointer that points to the first char of the array : %p\n", *str);
printf("address of the first char of the array: %p\n", &(**str));
printf("address of the seconds char of the array: %p\n", &((*str)[1]));
printf("value of the first char of the array : %c\n", **str);
printf("value of the second char of the array : %c\n", *(*str + 1));
printf("value of the second char of the array : %c\n", (*str)[1]);
printf("*str[1] is the same as *(str[1]), which runs to a segmentation fault\n");
return 0;
}
The output:
address of the pointer that points to a pointer that points the first char of the array : 0x7ffce24333f8
value of the pointer that points to a pointer that points to the first char of the array : 0x7ffce2433430
address of the pointer that points to the first char of the array : 0x7ffce2433430
value of the pointer that points to the first char of the array : 0x55a91985a2a0
address of the first char of the array: 0x55a91985a2a0
address of the seconds char of the array: 0x55a91985a2a1
value of the first char of the array : a
value of the second char of the array : b
value of the second char of the array : b
*str[1] is the same as *(str[1]), which runs to a segmentation fault
0x7ffce24333f8 0x7ffce2433430
+----------------+ +----------------+ +----------------+
| 0x7ffce2433430 | -------> | 0x55a91985a2a0 | -------> | a | 0x55a91985a2a0
+----------------+ +----------------+ +----------------+
+----------------+
| b | 0x55a91985a2a1
+----------------+
+----------------+
| c | 0x55a91985a2a2
+----------------+
The point is that it matters which pointer you dereference.
At least this problem:
Off by one
str[count] = '\0'; can write outside array bounds leading to OP''s trouble. Suggest count < size --> count + 1 < size.
Entire line not always read
Reading a partial line leads to trouble.
How about reading the entire line and report results? Let calling code provide the buffer as it is of fixed size.
Distinguish between reading an empty line and end-of-file.
Handle size == 0 gracefully.
// EOF: end-of-file with no input
// EOF: input error
// 0: input, but too much
// 1: Success
int secureInput(char *str, size_t size) {
if (str == NULL) {
size = 0;
}
bool too_many = false;
size_t count = 0;
int c;
while((c = getchar()) != '\n') {
if (c == EOF) {
if (feof(stdin) && count > 0) {
break;
}
if (size > 0) {
str[0] = '\0';
}
return EOF;
}
if (count + 1 < size) {
str[count++] = c;
} else {
too_many = true;
}
}
if (count < size) {
str[count] = '\0';
}
return count < size && !too_many;
}
I am new to C but I am trying to edit a struct in a different function. I can print the value of the struct correctly from the target function readCoordinate but when execution returns to the main function the values of the struct changes to a seemingly random integers.
This is the full code below.
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int X;
int Y;
} Coordinate;
void buff_clr(void)
{
char junk;
do{
junk=getchar();
}while(junk!='\n');
}
int main()
{
Coordinate carrierStart = {0,0};
printf("Input Start coordinate for Carrier (example - B2) \n");
readCoordinate(&carrierStart);
printf("%d, %d \n", carrierStart.X, carrierStart.Y);
}
void readCoordinate(Coordinate *cood){
char str[2];
scanf("%s",&str);
buff_clr();
if (isalpha(str[0]) )
{
str[0] = tolower(str[0]);
findChar(str[0], &cood->X);
cood->Y = (str[1] - '0') - 1;
}
else
{
printf("\n Please Enter Valid Coordinate");
exit(EXIT_SUCCESS);
}
printf("%d, %d \n", cood->X, cood->Y);
return;
}
void findChar(char find, int *x){
char vertical_letters[10] = {'a','b','c','d','e','f','g','h','i','j'};
for (int i = 0; i < 10; i++)
{
if (find == vertical_letters[i])
{
*x = i;
return;
}
}
*x = -1;
}
input of b2 should print 1,1 which is correct in function (readCoordinate) but wrong in Main.
The part
char str[2];
scanf("%s",&str);
is wrong because
&str has type char(*)[2], but %s in scanf expects char*. Passing data having the wrong type like this invokes undefined behavior.
char str[2]; is too short to store 2-character strings like b2 because there is no room for the terminating null character. You have to allocate enough elements.
You should specify the maximum length to read (the length of buffer minus one) to prevent buffer overrun.
It should be:
char str[3];
scanf("%2s",str);
I'm trying to understand what is wrong here.
void longestConsec(char* strarr[], int n) {
for(int i=0; i<n; i++)
{
printf("%s\n",strarr[i]);
}
}
int main()
{
char string[8][14] = {"zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"};
longestConsec(string, 8);
return 0;
}
I want to print every single word, and for some reason it doesn't work. What I think of is that strarr is array of pointer to char, so in every cell there should be a word, right? But when i tried to debug the code i saw that strarr and strarr[0] have different memory locations. Why?
strarr is an array of pointers to char, but string is not an array of pointers but an array of 14-element array of chars.
Pointers and 14-element array of chars may have different size, so your code won't work well.
How about using array of pointers like this?
#include <stdio.h>
void longestConsec(const char* strarr[], int n) {
for(int i=0; i<n; i++)
{
printf("%s\n",strarr[i]);
}
}
int main()
{
const char* string[8] = {"zone", "abigail", "theta", "form", "libe", "zas", "theta", "abigail"};
longestConsec(string, 8);
return 0;
}
Your compiler should have given you a warning that gives a good hint.
k.c:12:19: warning: passing argument 1 of ‘longestConsec’ from incompatible pointer type [-Wincompatible-pointer-types]
12 | longestConsec(string, 8);
| ^~~~~~
| |
| char (*)[14]
k.c:2:26: note: expected ‘char **’ but argument is of type ‘char (*)[14]’
2 | void longestConsec(char* strarr[], int n) {
| ~~~~~~^~~~~~~~
string is an array of arrays, char[8][14] and strarr is a pointer to pointer to char, char **. When string is passed to the function it decays to pointer to array of 14 char, char (*)[14]. Passing multidimensional arrays to functions can be tricky, but this works:
// size_t is better than int in this case
void longestConsec(size_t len, char strarr[][len], size_t n)
{
for(int i=0; i<n; i++)
printf("%s\n",strarr[i]);
}
And then call it with:
longestConsec(sizeof string[0]/sizeof string[0][0], // 14
string,
sizeof string/sizeof string[0] // 8
);
Note that you can write sizeof string[0] instead of sizeof string[0]/sizeof string[0][0] but that's because sizeof char is always 1.
Understanding these declarations can be a bit tricky. Just to give a type example of how they are declared:
char (*arr)[10]; // arr is a pointer to array of char of size 10
char *arr[10]; // arr is an array of 10 pointers to char
Related: arrays are not pointers and pointers are not arrays
my question is at the generate acronym function, how can i make this function work in a pointer arithmetic way instead of array subscripting.
without messing up with the structures itself, the prof prhobited array subscribting so i have to do it with pointer arithmetic instead, anyone can land a hand?
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define B 2
#define N 8
typedef struct {
int course_id;
int course_quota;
char course_name[50];
char course_code[6];
char course_acronym[N];
}course_t;
void generate_course_code(char *course_code, int course_id);
void generate_course_acronym(char *, char *);
void display();
course_t courses[B];
int main() {
int i;
for(i = 0; i < B; i++) {
printf("Enter the course name: ");
fgets(courses[i].course_name, sizeof(courses[i].course_name), stdin);
generate_course_acronym(courses[i].course_name, courses[i].course_acronym);
printf("Enter the course Quota: ");
scanf("%d", &courses[i].course_quota);
while ('\n' != getchar())
{
}
courses[i].course_id = i;
generate_course_code(courses[i].course_code, courses[i].course_id);
}
display();
return 0;
}
void generate_course_code(char *course_code, int course_id) {
char str[6];
course_id++;
strcpy(course_code, "CSE");
if (course_id < 10) {
sprintf(str, "0%d", course_id);
}
else
sprintf(str, "%d", course_id);
strcat(course_code, str);
}
void generate_course_acronym(char *course_name, char *course_acronym) {
int j = 0;
char *p = course_name;
for (course_acronym[j++] = toupper(*p); *p != '\0'; p++)
if (*p == ' ') course_acronym[j++] = toupper(*(++p));
course_acronym[j] = '\0';
}
void display() {
int x;
for (x = 0; x < B; x++) {
printf("%d. %s - %s (%s) - %d \n", ++courses[x].course_id, courses[x].course_code, courses[x].course_name, courses[x].course_acronym, courses[x].course_quota);
}
}
Because the function arguments are provided as pointers, they can be used as is to achieve your goal using pointer arithmetic as shown below:
(explanations in comments).
void generate_course_acronym(char *course_name, char *course_acronym)
{
*course_acronym = (char)toupper(*course_name); //initialize acronym to capitalized form of first character
while(*course_name) //test for end of string (NULL)
{
if(*course_name == ' ') // detect spaces between strings
{
course_acronym++; // advance acronym pointer
course_name++; // advance source pointer beyond space.
*course_acronym = (char)toupper(*course_name); // assign next acronym character
}
course_name++; // advance source to next address location
}
course_acronym++; // advance pointer to one location beyond end of acronym
*course_acronym = '\0'; // NULL terminate, making acronym a new string
}
Note: The calling function must pass enough space in course_acronym to accommodate 1 byte for each word in course_name, + 1 extra byte. For example, if course_name is defined as:
char course_name[]={"This is a fine programming class"};
then course_acronym must be defined with space for at least 7 bytes. (count of words + 1 for NULL termination)