Printing characters with a pointer's function - c

#include "head.h"
void readText(char *buffer)
{
char c;
int count=0;
char *newBuffer =(char *)calloc(SIZE,sizeof(char));
if(newBuffer==NULL)exit(1);
int i=1;
while ((c = getchar()) != EOF)
{
if (count % SIZE == 0)
{
i++;
newBuffer = (char *)realloc((char *)buffer,i*SIZE);
if(newBuffer==NULL){
printf("Not enought space, bye");
exit(1);
}else{
buffer=newBuffer;
}
}
if (c != '\n'){
*buffer++ = c;
count++;
}
}
}
int main()
{
int choose;
char *buffer;
printf("Please choose the desired method:\n Press 0 for buffer-method.\nPress 1 for Linked List method\n");
scanf("%d", &choose);
buffer = (char *)calloc(SIZE, sizeof(char));
if (buffer == NULL){
printf("Something went wrong, please try again\n");
exit(1);
}
readText(buffer);
printf("%s", buffer);
free(buffer);
return 0;
}
}
So I have been tasked with writing a function, that reads text and each time it passes 60 characters, i need to do realloc. Now everything works till I use called, meaning if I get more then 60 characters from the user, I get an error, and the terminal points to a problem with the realloc.
Whats the problem?

Related

how to extract numbers from char array and add them up

i want to get input from the user to get the name, then check the input against a char array filled by an external text file, then store the number associated with the name to a variable and be able to add up the number with any more that is associated with the same name
code:
int cnt_space(int i, int count, char input[], char strIndex)
{
strIndex = input[0];
while (strIndex != '\0'){
strIndex = input[i];
if (isspace(strIndex))
count++;
i++;
}
return (count);
}
/*bool divisable5()
{
}*/
char * dispChange(char name[])
{
enum { MAXL = 40, MAXC = 50 };
char (*lines)[MAXC] = NULL; /* pointer to array of type char [MAXC] */
int i, n = 0, index;
FILE *fp = fopen("coins.txt", "r");
if (!fp) { /* valdiate file open for reading */
printf ("failed to open file");
}
if (!(lines = malloc (MAXL * sizeof *lines))) { /* allocate MAXL arrays */
fprintf (stderr, "error: virtual memory exhausted 'lines'.\n");
}
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
int *change = 0, finalChange = 0;
char changeStr[2];
changeStr[0] = 0;
/* print lines */
for (i = 0; i < n; i++){
if (strstr(lines[i], name) != NULL){
for (index = 0; index < strlen(lines[i]); index++){
if(isdigit(lines[i][index])){
printf("test %s %d", lines[i], lines[i][index]);
if(changeStr[0] == 0){
changeStr[1] = "1";
printf("%s", changeStr);
strcpy(changeStr, lines[i][index]);
}
else{
strcat(changeStr, lines[i][index]);
}
}
}
sscanf(changeStr, "%d", change);
finalChange += change;
main();
}
else if (i == n-1 && strstr(lines[i], name) == NULL){
printf("Name not found, please try again\n\n");
dispChange(name);
}
}
printf ("Customer:\n%s%dcents\n\n", name, finalChange);
free (lines); /* free allocated memory */
}
char * getName()
{
char ch;
int i = 0, count = 0;
char name[100];
printf("Enter a name(spaces not accepted): ");
fgets(name, sizeof name, stdin);
count = cnt_space(i, count, name, ch);
if (count > 1){
printf("Error: Spaces not accepted!\n\n");
free(name);
getName();
}
else{
dispChange(name);
}
}
int main()
{
int choice;
char option[100];
printf("1. Enter Name\n2. Exit\n------------------\nEnter option: ");
fgets(option, sizeof option, stdin);
if (option[1] != '\n'){
printf("Invalid entry!\n\n");
main();
}
else{
choice = (int)option[0];
if (isdigit(choice)){
if (choice == 49){
getName();
}
else if (choice == 50){
printf("Program has ended\n");
exit(0);
}
else{
printf("Invalid option!\n\n");
main();
}
}
else{
printf("Invalid entry!\n\n");
main();
}
}
return 0;
}
somehow doing lines[i][index] does not get the number? it should get number 3 but its getting number 51
text file contains:
Justin 60
Jane 30
Jared 90
MinZhan 95
Andreas 80
GuoCong 95
David 45
Ngiap 35
Teng 10
Teow 95
To answer your question, it IS getting 3 as an ASCII character, which has a decimal value of 51. You are printing it with %d, which is the decimal formatter.
There are, however, a lot of things going on in this program.
The first is cnt_space:
int cnt_space(int i, int count, char input[], char strIndex)
{
strIndex = input[0];
while (strIndex != '\0'){
strIndex = input[i];
if (isspace(strIndex))
count++;
i++;
}
return (count);
}
You are always passing 0 for i, the start of the string, so you do not need to pass i at all. You are also always passing 0 for count, and thus do not need to pass count at all. You are also passing ch, which is never read but only written to, so should be declared only in cnt_space. But you do not even need an actual count, you just need to know if the name contains a space character at all, which you can determine with a function like strpbrk. I would remove your cnt_space function entirely and replace it with:
// these values came from the man page for isspace
if (strpbrk(name, " \f\n\r\t\v")) {
printf("Error: Spaces not accepted!\n\n");
continue;
}
You'll notice I put continue in the code, which doesn't quite fit with what you've got because you recursively call main. That's typically frowned upon, and I changed it to continue in anticipation of replacing this with some kind of loop.
Going to skip over dispChange for a minute and look at your getName function:
char * getName()
{
char ch;
int i = 0, count = 0;
char name[100];
printf("Enter a name(spaces not accepted): ");
fgets(name, sizeof name, stdin);
count = cnt_space(i, count, name, ch);
if (count > 1){
printf("Error: Spaces not accepted!\n\n");
free(name);
getName();
}
else{
dispChange(name);
}
}
Good practice would be to make this function static, as it is only called within this file. You also specify that it returns a character pointer, but it does not actually return anything. If you want to keep this as the caller to dispChange, I would recommend changing the return type to void since there is no return, and changing the function name to reflect this. The recursive call should be replaced with a loop in this case to prevent a literal stackoverflow. Also, you free name but free is to return memory to the heap (from malloc or some other memory allocation). You are calling it on the stack, which I would imagine crashes. I would rewrite it to look more like this:
static void getNameAndDisplayChange()
{
char name[100];
do {
printf("Enter a name(spaces not accepted): ");
fgets(name, sizeof(name), stdin);
// these values came from the man page for isspace
if (strpbrk(name, " \f\n\r\t\v")) {
printf("Error: Spaces not accepted!\n\n");
continue;
}
dispChange(name);
} while (0);
}
Now let's take a look at main, before we get into the weeds of dispChange. You had:
int main()
{
int choice;
char option[100];
printf("1. Enter Name\n2. Exit\n------------------\nEnter option: ");
fgets(option, sizeof option, stdin);
if (option[1] != '\n'){
printf("Invalid entry!\n\n");
main();
}
else{
choice = (int)option[0];
if (isdigit(choice)){
if (choice == 49){
getName();
}
else if (choice == 50){
printf("Program has ended\n");
exit(0);
}
else{
printf("Invalid option!\n\n");
main();
}
}
else{
printf("Invalid entry!\n\n");
main();
}
}
return 0;
}
The C standard allows void arguments to main, though you may make your program more flexible by taking argc and *argv[] to accept a name on input. There are better ways to validate the input here, but we can clean it up a lot just by changing the recursion. I would also recommend using defines such as EXIT_SUCCESS and EXIT_FAILURE instead of return 0. Instead of converting the input to an integer and using the ASCII values to determine the action, you can use strcmp to keep it more readable. I would also recommend creating a "readline" function that strips the newline from user input to make it even more readable, but you can do that later. The refactored main would look something like:
int main()
{
char option[100] = "\0";
while (strcmp(option, "2") != 0) {
printf("1. Enter Name\n2. Exit\n------------------\nEnter option: ");
fgets(option, sizeof(option), stdin);
if (strcmp(option, "1\n") != 0 && strcmp(option, "2\n") != 0) {
printf("Invalid entry: %s!\n\n", option);
continue;
}
if (strcmp(option, "2\n") == 0) {
printf("Program has ended\n");
break;
}
getNameAndDisplayChange();
}
return EXIT_SUCCESS;
}
For dispChange, typically with a function this big I would recommend breaking it into smaller functions, but I think we can shrink it quite a bit:
char * dispChange(char name[])
{
enum { MAXL = 40, MAXC = 50 };
char (*lines)[MAXC] = NULL; /* pointer to array of type char [MAXC] */
int i, n = 0, index;
FILE *fp = fopen("coins.txt", "r");
if (!fp) { /* valdiate file open for reading */
printf ("failed to open file");
}
if (!(lines = malloc (MAXL * sizeof *lines))) { /* allocate MAXL arrays */
fprintf (stderr, "error: virtual memory exhausted 'lines'.\n");
}
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
int *change = 0, finalChange = 0;
char changeStr[2];
changeStr[0] = 0;
/* print lines */
for (i = 0; i < n; i++){
if (strstr(lines[i], name) != NULL){
for (index = 0; index < strlen(lines[i]); index++){
if(isdigit(lines[i][index])){
printf("test %s %d", lines[i], lines[i][index]);
if(changeStr[0] == 0){
changeStr[1] = "1";
printf("%s", changeStr);
strcpy(changeStr, lines[i][index]);
}
else{
strcat(changeStr, lines[i][index]);
}
}
}
sscanf(changeStr, "%d", change);
finalChange += change;
main();
}
else if (i == n-1 && strstr(lines[i], name) == NULL){
printf("Name not found, please try again\n\n");
dispChange(name);
}
}
printf ("Customer:\n%s%dcents\n\n", name, finalChange);
free (lines); /* free allocated memory */
}
Again, I would make it static as it is confined to this file. It also does not return anything, so I would change the return type to void. Since we aren't changing name, I would let the caller know that by defining it as const as well.
There are some flaws in this function, you read from fp even if it is determined the file could not be opened. You compare fp to stdin, which I don't see a way for that to happen right now (maybe a feature enhancement?). If you have to read from stdin, it makes sense that you would want to load it all into memory, but you'll definitely want to do that once and outside of this function. strstr is used in such a way that it may match unintended names, such as "Charley" will match "O'Charley". To fix that, you will want to make sure that the name matches the start of the line, and that it ends in a space. strlen is computed inside of a loop, which is just wasted CPU cycles, since the length won't change.
You can reduce a lot of complexity and increase scalability by operating on the file one line at a time, instead of loading it all into memory. Again, if you have to support stdin, you will not want to make this change, but rather have a separate function that loads a FILE * into an array, something like loadData(FILE *fp, lines). This refactor is based on how your sample works, iterating through the file for every name.
static void dispChange(const char name[])
{
enum { MAXC = 50 };
char line[MAXC];
int nameLen = strlen(name);
FILE *fp = fopen("coins.txt", "r");
if (!fp) { /* valdiate file open for reading */
printf ("failed to open file\n");
return;
}
int finalChange = 0;
while (fgets(line, MAXC, fp)) { /* read each line */
if (strstr(line, name) == line && line[nameLen] == ' ') {
int change;
sscanf(&line[nameLen + 1], "%d", &change);
finalChange += change;
}
}
fclose(fp);
printf ("Customer:\n%s %d cents\n\n", name, finalChange);
}
I hope this is helpful, and not just me doing the assignment for you.

C Program Segmentation Fault main()

I am novice to C programming and I have written a code to a requirement specification but I am consistently getting Segmentation Fault and unable to proceed ahead.
If the file name is 'code.c' and it runs with an error of not passing the argument (filename). But if the filename is passed, we land in Segmentation Fault.
Any help/suggestions will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
int ch = 0, lines = 0;
while (!feof(*stream))
{
ch = fgetc(*stream);
if (ch == '\n')
{
lines++;
}
}
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int size)
{
int i;
size_t chrCount;
char *text, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(size, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
rewind(stream);
for (i = 0; i < size; i++)
{
getline(&text, &chrCount, stream);
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char *name, int size, int inputs)
{
int i;
int found = 0;
char *search = " ";
char *firstName;
char *lastName;
if (inputs == 2)
{
firstName = strtok(name, search);
lastName = strtok(NULL, search);
}
printf("*******************************************\n");
if (inputs == 2)
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) && !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
else
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) || !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
if (found == 0)
{
printf("The name was NOT found.\n");
}
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int size)
{
int i;
for (i = 0; i < size; i++)
{
free(BlackBox[i].firstName);
free(BlackBox[i].lastName);
}
free(BlackBox);
BlackBox = NULL;
}
// MAIN
int main(int argv, char **argc)
{
int size;
FILE *stream;
struct _data *BlackBox;
// argv == 1 WORKS, Below message is printed.
if (argv == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argv == 2 DOES NOT WORK, Segmentation Fault.
if (argv == 2)
{
size = SCAN (&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[1], size, 1);
}
if (argv == 3)
{
size = SCAN(&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[2], size, 2);
}
return 0;
}
You have a problem in this code:
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
...
BlackBox[i].number = atol(number);
The second strtok() call should pass NULL as its first argument. As it is, the third strtok() call is certain to return NULL because the first call modifies text in such a way that the second consumes the whole thing (when tokenizing again from the beginning, as it erroneously does). You do not test for that, however, and as a result, atol() attempts to dereference a null pointer.
Update:
Additionally, as #chqrlie and later #JamesWilkins observed, you do not allocate sufficient space for BlackBox[i].firstName and BlackBox[i].lastName, as you need room for the string terminators as well. This is an entirely separate problem that could also produce a segfault. I like #chqrlie's suggestion to switch to strdup(), but it would be sufficient to just increase each allocation by one unit.
Update 2:
Furthermore, you have an issue with this line:
getline(&text, &chrCount, stream);
You do not initialize variable text before the first call, so it contains a junk value. The function allocates a buffer only when its first argument points to a NULL pointer; otherwise it writes the line to the buffer pointed to by the pointer obtained by dereferencing the first argument. Writing to a random location in memory certainly produces undefined behavior, which in practice often manifests as a segfault.
Moreover, unless you can rely on no line of the file being longer than the first, you also need to free the text pointer at the end of each loop iteration AND reset its value to NULL, so that getline() allocates a fresh buffer on the next iteration. If you do not free it on each iteration, then you need instead to free it after the end of the loop; else you will leak memory.
Try this (though I'm using Visual Studio on Windows). I added code to check for a missing '\n' on the last line, and also allowed for a variable number of search terms. I also increased the memory allocation for strings by 1 to account for the null terminating character. I noticed you are using getline(const char*..., which I think is GNU (Linux?), so I change that to fgets() just so I could compile and test it in VS (so you can change it back if you like). I put in various null checks as well, to be safer.
#include <iostream>
using namespace std;
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
if (*stream == NULL)
{
perror("Error opening file");
return 0;
}
char ch = 0, lines = 0, linesize = 0;
while ((ch = fgetc(*stream)) != EOF)
{
if (ch == '\n')
{
lines++;
linesize = 0;
}
else linesize++;
}
if (linesize > 0)
lines++; // (last line doesn't have '\n')
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int lineCount)
{
int i;
size_t chrCount = 256;
char text[256], *result, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(lineCount, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
else memset(BlackBox, 0, sizeof(struct _data) * lineCount); // (make sure all data members are null to begin)
rewind(stream);
for (i = 0; i < lineCount; i++)
{
result = fgets(text, chrCount, stream);
if (result == NULL)
break; // (EOF)
firstName = strtok(text, " ");
lastName = strtok(NULL, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char **names, int lineCount, int inputs)
{
int i, l;
int found = 0;
printf("*******************************************\n");
for (i = 0; i < inputs; ++i)
{
for (l = 0; l < lineCount; ++l)
{
if (BlackBox[l].firstName != NULL && !_stricmp(names[i], BlackBox[l].firstName)
|| BlackBox[l].lastName != NULL && !_stricmp(names[i], BlackBox[l].lastName))
{
printf("The name was found on line %d.\n", 1 + l);
found = 1;
break;
}
}
if (found) break;
}
if (!found)
printf("The name was NOT found.\n");
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int lineCount)
{
int i;
for (i = 0; i < lineCount; i++)
{
if (BlackBox[i].firstName != NULL)
free(BlackBox[i].firstName);
if (BlackBox[i].lastName != NULL)
free(BlackBox[i].lastName);
}
free(BlackBox);
}
// MAIN
int main(int argc, char **argv)
{
int lineCount;
FILE *stream;
struct _data *BlackBox;
// argc == 1 WORKS, Below message is printed.
if (argc == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argc == 2 DOES NOT WORK, Segmentation Fault.
if (argc > 1)
{
lineCount = SCAN(&stream);
if (lineCount > 0)
{
BlackBox = LOAD(stream, lineCount);
SEARCH(BlackBox, argv + 1, lineCount, argc - 1);
FREE(BlackBox, lineCount);
}
}
return 0;
}
Tested it on the command line, and it works.
The problem is the argv and argc. argc is supposed to be an int (think argument count), while argv is meant to be char**. You have them mixed up in your main.

Reading word by word from text file in C

I am very new to C. I am trying to read the words from a file which contains lots of not alpha characters. My input file looks something like this %tOm12%64ToMmy%^$$6 and I want to read tom first and then put tom in my data structure and then read tommy and put that in my data structure all in lowercase. This is what I have tried until now. All my other code works as I have manually sent the parameters to the methods and there are no errors. This is what I have tried to read the words from the file. A word can be of 100 characters max. Can someone help me understand the logic and possibly this code.I am very lost.Thank You!
void read(FILE *fp)
{
FILE *fp1 = fp;
char word[100];
int x;
int counter = 0;
while ((x = fgetc(fp1)) != EOF)
{
if (isalpha(x) == 0)
{
insert(&tree,word);
counter = 0;
}
if (isalpha(x) != 0)
{
tolower(x);
word[counter] = x;
counter++;
}
}
rewind(fp1);
fclose(fp1);
}
char *getWord(FILE *fp){
char word[100];
int ch, i=0;
while(EOF!=(ch=fgetc(fp)) && !isalpha(ch))
;//skip
if(ch == EOF)
return NULL;
do{
word[i++] = tolower(ch);
}while(EOF!=(ch=fgetc(fp)) && isalpha(ch));
word[i]='\0';
return strdup(word);
}
void read(FILE *fp){
char *word;
while(word=getWord(fp)){
insert(&tree, word);
}
//rewind(fp1);
fclose(fp);
}
This is a simplification of #BLUEPIXY 's answer. It also checks the array boundaries for word[]
char *getword(FILE *fp)
{
char word[100];
int ch;
size_t idx ;
for (idx=0; idx < sizeof word -1; ) {
ch = fgetc(fp);
if (ch == EOF) break;
if (!isalpha(ch)) {
if (!idx) continue; // Nothing read yet; skip this character
else break; // we are beyond the current word
}
word[idx++] = tolower(ch);
}
if (!idx) return NULL; // No characters were successfully read
word[idx] = '\0';
return strdup(word);
}

*** glibc detected *** invalid pointer: 0x00000031bee21188

I've looked through similar questions on stackoverflow, but I'm still not sure how to fix it.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
extern char * pop();
extern void push(char *);
int i;
int j=0;
//Resize the array to 1.1 it's size
void reSize(char* tag){
char *temp = malloc(1.1*sizeof(tag));
for (i=0;i<(sizeof(tag)/sizeof(tag[0]));i++){
*(temp+i) = *(tag+i);
}
free(tag);
tag = temp;
}
int compare(char* tag, char* popVal){
i=0;
while (i<sizeof(tag)/sizeof(tag[0])){
if (*(tag+i) == *(popVal+i)){
i++;
}else{
return 0;
}
}
return 1;
}
void dothis(){
int ch;
int n=0;
char *tag = malloc(10* sizeof(char));
char *popVal;
while ((ch = getchar()) != '>'){
tag[n] = ch;
n++;
if (n > (sizeof(tag)/sizeof(tag[0]))-1 ){
reSize(tag);
}
}
if (*tag == '/'){
popVal = malloc(sizeof(tag));
popVal = pop();
j--;
if (!(compare(tag,popVal))){ // Compare will return 1 if the same
printf("Invalid");
exit(1);
}
}else{
push(tag);
j++;
}
free(tag);
free(popVal);
}
int main(int argc, char * argv[])
{
int ch;
while ((ch = getchar()) != EOF) {
if (!(isalpha(ch) || ch == '<'))
continue;
dothis();
}
if (j != 0){
printf("Invalid\n");
exit(1);
}
printf("Valid\n");
exit(0);
}
then the external methods:
#include <stdio.h>
#include <stdlib.h>
static int top = 0;
static char * stack[100];
int isEmpty()
{
return !(top);
}
char * pop()
{
if (isEmpty()){
fprintf(stderr, "Stack is empty");
exit(1);
}
top--;
return (char *) stack[top];
}
void push(char * thing2push)
{
if (top == 100){
fprintf(stderr, "Too many things in the stack");
exit(1);
}else{
stack[top] = thing2push;
top++;
}
}
In a previous question, the selected answer was "passing a pointer to memory you haven't allocated with malloc will definitely not do good things.", but I"m pretty sure I allocated everything
Here's a bug:
popVal = malloc(sizeof(tag));
popVal = pop();
You malloc an area and then immediately lose that value, replacing it with something from pop().
This is most definitely a bug:
while ((ch = getchar()) != '>'){
tag[n] = ch;
n++;
if (n > (sizeof(tag)/sizeof(tag[0]))-1 ){
You assign to tag[n] before checking the range of n. When you do check the range of n after the fact you use sizeof(tag). tag is a pointer. It's size is 4 (32 bit) or 8 (64 bit). Neither size has anything to do with how big n can be before tag[n] writes into invalid memory.
Another bug:
char * pop()
{
if (isEmpty()){
fprintf(stderr, "Stack is empty");
exit(1);
}
top--;
return (char *) stack[top];
}
If you're a beginning C programmer, never cast a pointer. Because I doubt that you have learned enough yet to know if this is a good or bad idea.
The type system exists for good reasons and if it complains about some types not matching, it is far more likely to be right than you are.

string in place of int in c

//why the code starts printing retry infinitely if i wrongly
enter a string in place of int i in terminal
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char const *argv[])
{
int i,j=0;
while(1)
{
scanf("%d",&i);
if(i==10)
{
printf("you got the max! YOU WON\n");
break;
}
else
{
printf("%s\n","retry" );
}
}
return 0;
}
Try consuming (flushing) on bad input:
else {
while ((j = fgetc(stdin)) != '\n' && j != EOF);
printf("%s\n", "retry");
}
An alternative using fgets (is preferable because it consumes the whole line) and strtol:
#include <stdio.h> /* fgets, printf */
#include <stdlib.h> /* strtol */
#include <string.h> /* strchr */
int main(void) /* No args */
{
char buf[128], *p;
int i;
while (fgets(buf, sizeof(buf), stdin)) {
if ((p = strchr(buf, '\n')) != NULL) {
*p = '\0'; /* remove newline */
}
i = (int)strtol(buf, &p, 10); /* Base 10 */
if (*p != '\0' || i != 10) {
printf("retry\n");
} else {
printf("you got the max! YOU WON\n");
break;
}
}
return 0;
}
Read fails because of you inputted wrong type and i will have garbage value.
Add initialization to i:
int i=0, j=0;
scanf returns number of succesful reads. Add return value check to scanf:
int r = scanf("%d",&i); // Will return 1 if 1 argument was successully read
if(r == 1 && i == 10)
{
//do something
}
Edit:
As others have pointed out, it seems that scanf doesn't consume incoming bytes if input is wrong. Thus you might want to replace it wit fgets and sscanf:
int r;
char temp[32];
fgets(temp, 32, stdin); // Read input to temporary buffer
r = sscanf(temp, "%d", &i); // Try to convert value on buffer
if(r == 1 && i == 10)
{
//do something
}

Resources