Reversing string using stack - c

I have a problem with reversing string using stack structure.
I made some code to reverse 'apple' to 'elppa' and seems like it worked well...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_STACK_SIZE 5
typedef int element;
element stack[MAX_STACK_SIZE];
int top = -1;
void initialize() {
top = -1;
}
int isEmpty() {
return (top == -1);
}
int isFull() {
return (top == (MAX_STACK_SIZE - 1));
}
void push(element item) {
if (isFull()) {
printf("stack is full, cannot add element.\n");
}
else{
stack[++top] = item;
}
}
element pop() {
if (isEmpty()) {
printf("stack is empty\n");
}
else {
return stack[top--];
}
}
char* reverse(char* s) {
const int len = sizeof(s) + 1;
char* rstring = new char[len];
initialize();
for (int i = 0; i < len; i++) {
push(s[i]);
}
int tmp = 0;
while(isEmpty()==false){
rstring[tmp++]=pop();
}
for (int i = 0; i < len; i++) {
printf("%c\n", rstring[i]);
}
return rstring;
}
void main() {
char* str1 = "apple";
char* str2 = reverse(str1);
printf("before : %s \n", str1);
printf("after : %s \n", str2);
getchar();
}
the result is here I got the answer(elppa) but it also printed out some other characters what I wasn`t intended. Why I got this thing? It may something to do with memory array or something but do not know exactly what was happened memory. How to fix the problem?

You haven't taken into account the string termination character '\0'. You are printing the sting using %s with printf.
Once rstring has been calculated after unwinding the stack, you should append '\0' to rstring. Hopefully this will solve your problem.

By using sizeof you will get the data_type size (in this case, size of char*) in bytes. You should use strlen instead.

Related

Does returning a pointer from a function make it invalid to reallocate?

So I'm currently trying to write a C program to track the longest word(s) from argv.
It's been going great! Until I tried to reallocate a character double pointer, it seems to think it's an invalid pointer.
The exact error I'm getting is;
realloc(): invalid pointer
fish: Job 1, './longest-strings.o hello...' terminated by signal SIGABRT (Abort)
I'm creating this double character pointer through the return of a function, is this possibly the error? I'm pretty sure my use of realloc is correct, and I can't quite seem to trace the issue.
Any help would be massively appreciated!
/*
* Author: Smallblue2
* Description: Program finds the longest word in an input string
*
* Input: A string from cmd line
* Output: The longest word in a string
*/
// Header files
#include <stdio.h>
#include <stdlib.h>
// Function prototypes
int stringLength(char *string);
void longestWords(char **strings, int amt);
char **reset(char *string);
void display(char **longest, int len_array);
// Main function
int main(int argc, char **argv)
{
char **strings = &*(argv + 1);
longestWords(strings, argc - 1);
return 0;
}
// Find the length of a string
int stringLength(char *string)
{
int length = 0;
while (*string != '\0')
{
length++;
string++;
}
return length;
}
// Finds the longest word(s) from argv
void longestWords(char **strings, int amt)
{
// Set up variables & pointers
int len_array = 1;
// Assign the first string to be the longest
char **longest = reset(*(strings));
int longest_len = stringLength(*(longest));
int length = 0;
// Loop through the rest of the strings
for (int i = 1; i < amt; i++)
{
// Find the length of the current string
length = stringLength(*(strings + i));
// If it is larger, reset the longest array and place the
// new string inside
if (length > longest_len)
{
longest_len = length;
longest = reset(*(strings + i));
len_array = 1;
// Else, expand the longest array's memory and add the
// additional string inside
} else if (length == longest_len) {
len_array++;
char **temp_longest = (char **)realloc(longest, len_array * sizeof(char *));
if (!longest)
{
printf("Error: Memory allocation failed!\n");
free(longest);
return;
}
longest = temp_longest;
*(longest + len_array - 1) = *(strings + i);
}
}
// Display the longest word(s)
display(longest, len_array);
free(longest);
longest = NULL;
return;
}
// Resets the longest word array
char **reset(char *string)
{
char **longest = (char **)malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
longest = &string;
return longest;
}
// Displays the longest word(s)
void display(char **longest, int len_array)
{
for (int i = 0; i < len_array; i++)
{
printf("%s\n", *(longest + i));
}
return;
}
I've tried to use both calloc and malloc, I tried executing the script where realloc wouldn't occur and then apparently free() believes there's an invalid pointer too. Really lost here.
Here are the two minimal changes:
stringLength should handle a NULL pointer.
int stringLength(char *string)
{
int length = 0;
while (string && *string != '\0')
{
length++;
string++;
}
return length;
}
Or perhaps:
#include <string.h>
size_t stringLength(char *string)
{
return string ? strlen(string) : 0;
}
reset() leaks the memory you just allocated, and you don't want to take the address of an argument which is out of scope when the function returns. Not entirely sure what the point of the function is but try this instead:
char **reset(char *string)
{
char **longest = malloc(sizeof(char *));
if (!longest)
{
printf("Error: Memory Allocation Failed!\n");
return NULL;
}
*longest = string;
return longest;
}
and example output:
$ ./a.out hello...
hello...
./a.out hello world!
world!

Invoking the function renders an error; what explains this?

A function I created, which I refer to as string_deletion, deletes occurrences of a specific substring and shifts the string leftwards by the length of the substring. The function accepts two parameters: the pointer to the location in the array wherein the first letter of the substring is encountered, and the length of the word.
Here is the function:
void string_deletion(char *s, int m)
{
char *index=s+m;
while(*index!=0)
{
*(index-m)=*(index++);
}
*(index-m)=0;
}
The function shifts all the characters after the substring leftwards by an amount dependent on the length of the substring, which has been denoted by m. I have set the index pointer to point to the character that occurs immediately after the occurrence of the substring, and this is the mark from where the shifting commences. The loop is executed until a NUL character is encountered, after which it exits the loop. At the culmination, the NUL is appended to the end of the string.
Whereas the other parts of the main code work seamlessly, invoking this specific function, as and when necessary, makes the program cease working and it yields an error. What explains this?
Here's the complete code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<limits.h>
int string_len(char *s)
{
int i=0;
char *m=s;
while(*m!=0)
{
i++;
m++;
}
return i;
}
void word_enter(char *word_search)
{
char r;
char *m=word_search;
while((r=getchar())!=EOF)
{
if(r=='\n')
{
*m=0;
break;
}
else
{
*(m++)=r;
}
}
}
void string_disp(char *s)
{
char *d=s;
while(*d!=0)
{
putchar(*(d++));
}
}
int string_comp(char *s, char *m)
{
int stringlength_one=string_len(s);
int stringlength_two=string_len(m);
char *s_one=s;
char *s_two=m;
if(stringlength_one!=stringlength_two)
{
return 1;
}
else
{
while(*s_one!=0)
{
if(*s_one!=*s_two)
{
return 1;
}
s_one++;
s_two++;
}
}
return 0;
}
void string_deletion(char *s, int m)
{
char *index=s+m;
while(*index!=0)
{
*(index-m)=*(index++);
}
*(index-m)=0;
}
void string_search(char *s,char *d)
{
char *m=s;
char word_buffer[20];
char *buffer_index=word_buffer;
while(m!=&s[string_len(s)-string_len(d)+1])
{
buffer_index=word_buffer;
if(*m==*d)
{
int i=0;
char *r=m;
while(i<=string_len(d) && *r!=0)
{
*(buffer_index++)=*(r++);
i++;
}
*buffer_index=0;
if(string_comp(word_buffer,d)==0)
{
printf("\nInvoking deletion sequence\n");
string_deletion(m,string_len(d));
}
}
m++;
}
}
int main(void)
{
int pos;
char main_string[100],word[20];
printf("Enter the main string: ");
word_enter(main_string);
printf("\nEnter the string you wish to delete: ");
word_enter(word);
string_search(main_string,word);
string_disp(main_string);
exit(EXIT_SUCCESS);
}
*(index-m)=*(index++)
This is undefined behaviour. If you use a post- or pre-inc/decrement, don't use the same variable in the same expression again.
index[-m] = *index;
++index;
The problem (or, at least, one problem) is in your string_search function. The substring you extract from the given s argument is one character too long; thus, you won't get a match with the given d argument, unless you are very lucky.
To fix the problem, change the test condition in the while loop from i <= string_len(d) to i < string_len(d), like this:
void string_search(char* s, char* d)
{
char* m = s;
char word_buffer[20];
char* buffer_index = word_buffer;
while (m != &s[string_len(s) - string_len(d) + 1]) {
buffer_index = word_buffer;
if (*m == *d) {
int i = 0;
char* r = m;
while (i < string_len(d) && *r != 0) { // Use i < string_len ... not i <=
*(buffer_index++) = *(r++);
i++;
}
*buffer_index = 0;
if (string_comp(word_buffer, d) == 0) {
printf("\nInvoking deletion sequence\n");
string_deletion(m, string_len(d));
}
}
m++;
}
}
Also, be sure to address the issue of undefined behaviour highlighted in this answer (my MSVC compiler didn't spot that one, but clang-cl did)!
I would not reinvent the wheel:
char *string_deletion(char *s, size_t m)
{
memmove(s, s + m, strlen(s+m) + 1);
return s;
}

snprintf with unknown size of the char[]

How one can create a char array with an unspecified size and then pass it to snprint for formatting it?
For example:
char str[];
int total = 100;
int points = 20;
snprintf(str, sizeof(str), "You have %d points (total: %d)", points, total);
printf("%s\n",str);
This code is going certainly send me an error because first line is wrong.
All the examples I saw on internet had something like str[100].
I am new to C programming and I would appreciate it if you don't down vote this post.
Thank you
At some point you must know how long your string will be. Simple examples like this you can just choose a sufficiently big number. You're doing the right thing using snprintf if you happen to be wrong at some point. In cases where this isn't possible snprintf returns the number of characters it will use if the first two parameters are NULL and 0. From there you malloc and free buffers determined at runtime.
size_t size = snprintf(NULL, 0, ...);
char* str = malloc(size);
snprintf(str, size, ...);
//After doing what you want with the string
free(str);
C doesn't work like your typical high-level language.
You are required to alloc every bit of memory you want to use (either be it on the stack or on the heap). That's why on the internet people usually do stuff like char str[100]: they are saying: I'm not expecting a string longer than 99 characters (+ '\0' char at the end of the string).
If you want your typical Java string, you need to create it yourself from scratch. Here's a demo of an implementation with no-so-good performances. variadic string api is left to the reader :)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
struct string_t {
///number of bytes of the string (\0 included)
size_t capacity;
///strlen of the string
size_t len;
///pointer to the actual string
char* str;
};
struct string_t* newString(const char* str);
void initString(struct string_t* this);
void destroyString(const struct string_t* this);
bool isEmpty(const struct string_t* this);
void tryExpand(struct string_t* this, size_t additionalSpace);
char* getNullTerminatorAddress(const struct string_t* this);
void setString(struct string_t* this, const char* other);
struct string_t* newString(const char* str) {
struct string_t* result = malloc(sizeof(struct string_t));
if (result == NULL) {
fprintf(stderr, "error!\n");
exit(1);
}
initString(result);
setString(result, str);
return result;
}
void initString(struct string_t* this) {
this->len = 0;
this->capacity;
this->str = 0;
}
void destroyString(const struct string_t* this) {
if (this->str != NULL) {
free((char*)this->str);
}
free((char*)this);
}
bool isEmpty(const struct string_t* this) {
return this->len == 0;
}
void tryExpand(struct string_t* this, size_t additionalSpace) {
if ((this->len + additionalSpace) > this->capacity) {
if (this->str != NULL) {
int newcapacity = this->len + additionalSpace;
this->str = realloc(this->str, newcapacity);
this->capacity = newcapacity;
} else {
this->str = malloc(sizeof(char) * additionalSpace);
if (this->str == NULL) {
exit(1);
}
}
}
}
void trySetting(struct string_t* this, size_t spaceRequired) {
if ((spaceRequired) > this->capacity) {
if (this->str != NULL) {
int newcapacity = spaceRequired;
this->str = realloc(this->str, newcapacity);
this->capacity = newcapacity;
} else {
this->str = malloc(sizeof(char) * spaceRequired);
if (this->str == NULL) {
exit(1);
}
this->capacity = spaceRequired;
}
}
}
char* getNullTerminatorAddress(const struct string_t* this) {
if (this->str != NULL) {
return &this->str[this->len];
} else {
exit(2);
}
}
void setString(struct string_t* this, const char* other) {
int alen = strlen(other);
trySetting(this, alen + 1);
//beware of buffer overrun
strcpy(this->str, other);
this->len = alen;
}
void appendString(struct string_t* this, const char* other) {
int alen = strlen(other);
tryExpand(this, alen + 1);
//beware of buffer overrun
strcpy(getNullTerminatorAddress(this), other);
this->len += alen;
}
void appendInt(struct string_t* this, int other) {
int bytes = snprintf( NULL, 0, "%d", other); //0 not considered
tryExpand(this, bytes + 1);
snprintf(getNullTerminatorAddress(this), bytes+1, "%d", other);
this->len += bytes;
}
const char* getString(const struct string_t* this) {
return (const char*)this->str;
}
int getLength(const struct string_t* this) {
return this->len;
}
int getCapacity(const struct string_t* this) {
return this->capacity;
}
int main() {
int points = 5;
int total = 10;
struct string_t* str = newString("You have ");
appendInt(str, points);
appendString(str, " points (total: ");
appendInt(str, total);
appendString(str, ")");
printf("%s\n", getString(str));
destroyString(str);
return 0;
}
Note you can retrieve the number of bytes to write in snprintf thanks to the trick of user2622016

How to check if a pointer has been freed

I am a beginner in C. Below is my scenario - I have created a pointer variable in main function and it has been passed on to several functions(in this example 2 levels). And one of the functions frees it up. Now I need to have check in Main to see whether the pointer is freed or not, that means i need to setup the value of &str in main() to point to NULL. Not sure my approach is right here. Any help would be much appreciated
void func2(char *str)
{
free(str);
}
void func1(char *str)
{
func2(str);
}
int main()
{
char *str;
str=(char *) malloc(10);
func1(str);
if(str){ do something; } // if condition to check whether str is freed
}
#include <stdio.h>
#include <stdlib.h>
func2(char **str)
{
free(*str); //free
*str = NULL; //Set to NULL
}
func1(char **str) //func1 receives as **
{
func2(str); //Pass pointer to func2()
}
int main()
{
char *str = NULL;
str=(char *) malloc(10);
func1(&str); //Pass Address of pointer to func1()
if(str) //Check for NULL
{
printf("\n Not - Freed...\n");
}
else
{
printf("\n Freed...\n");
}
return 0;
}
In C all are pass by value. I suggest to study http://www.cs.fsu.edu/~myers/cgs4406/notes/pointers.html for understanding of this.
You could try something like this - first redefine malloc and free (track.h)
#ifndef track_h
#define track_h
extern void* trackmalloc(size_t size);
extern void trackfree(void* array);
extern void trackismalloc(void* array);
#define malloc trackmalloc
#define free trackfree
#endif
Then for every piece of code that uses malloc and free, replace #include with #include "track.h"
#include <stdlib.h>
#include <stdio.h>
#include "track.h" /* was <malloc.h> */
// A function which has a 20% chance of freeing the pointer
void twentypercent(char* array)
{
if (rand() < (RAND_MAX / 5))
free(array);
}
int main(int argc, char* argv[])
{
char* list = malloc(256);
int ii;
for (ii = 0; ii < 10; ++ii)
twentypercent(list);
if (trackismalloc(list)
printf("Not freed yet");
return 0;
}
Now define track.c. This will only free memory that has been allocated by by trackmalloc. If it was not allocated by trackmalloc, then it will report that the memory has already been freed.
#include <stdio.h>
#include <malloc.h>
#define TRACKER_MAX 2048
static void* tracker[TRACKER_MAX] = { 0 };
static int track_last = -1;
void* trackmalloc(size_t size)
{
// For simplicity, tracker will not be reused
tracker[++track_last] = malloc(size);
return tracker[track_last];
}
void trackfree(void* array)
{
// This will slow down as the list gets filled up.
// You will need a more efficient way of searching lists (possibly bsearch)
int tt;
for (tt = 0; tt < track_last; ++tt)
{
if (array == tracker[tt])
{
free(tracker[tt]);
tracker[tt] = 0;
break;
}
}
if (tt == track_last)
printf("%p already freed\n", array);
}
int trackismalloc(void* array)
{
// This will slow down as the list gets filled up.
// You will need a more efficient way of searching lists (possibly bsearch)
int tt, result = 0;
for (tt = 0; tt < track_last; ++tt)
{
if (array == tracker[tt])
{
result = 1;
break;
}
}
return result;
}
void func1(char** str) {
free(*str);
*str = NULL;
}
void func2(char** str) {
free(*str);
*str = NULL;
}
int main() {
char *str;
str = (char*) malloc(10);
func1(&str);
if (str) {
do something;
}
}
void func2(char **str)
{
free(*str);
*str = 0;
}
void func1(char **str)
{
func2(str);
}
int main()
{
char *str;
// I'd recommend using sizeof(type_you_want) * amount_of_elements instead of
// a constant number: -> malloc(sizeof(char) * 10);
str=(char *) malloc(10);
func1(&str); // You must pass the address of the pointer, because you want
// to change "WHAT IT POINTS TO", not "WHAT IS POINTED BY IT"
if(str){ do something; } // if condition to check whether str is freed
}
When you call a function in C, you pass a copy of those arguments, so you are passing a copy of that pointer (that copy still points to the same place, so you can change that place that it points to) but you want to change the pointer value, so you need to pass its address.
I have explained a little bit how pointers inside functions can be used in here
#include <stdio.h>
#include <stdlib.h>
void func2(char **str)
{
printf("%d %s\n",__LINE__,__func__);
free(*str);
*str = NULL;
}
void func1(char **str)
{
printf("%d %s\n",__LINE__,__func__);
func2(str);
}
char * allocaMem(char **ptr)
{
*ptr=(char *) malloc(sizeof(char)* 10);
if(!*ptr)
{
perror("");
}
else
{
return *ptr;
}
}
int main()
{
char *str = allocaMem(&str);
if (!str) {
printf("Error in malloc()\n");
return -1;
}
func1(&str);
if (str) {
printf("Memory Not freed\n");
} else {
printf("Memory freed\n");
}
}

Program is causing a segmentation fault in VI but works fine in emacs

I'm not sure why my program will not compile right on vi. it only prints the first occurrence of the function show(var) and then exits and lists a segmentation fault and core dumped, however, it compiled without any errors on emacs and displayed all the strings after being quicksorted.
The program is supposed to read in data from a text file that I have stored in the same directory, and quicksort it using one of the 2 compare functions (which don't have to be meaningful, they just need to be functional) and then prints it out to the screen.
Thanks in advance.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
void show(void *array[]){
int i = 0;
while(array[i]!=NULL){
printf("String %d : %s\n",i, array[i]);
i++;
}
printf("\n");
}
void *readData(void * lineArray[]){
static const char filename[] = "sampledata.txt";
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
int i ;
char line [ 128 ]; /* or other suitable maximum line size */
void *lineadrs ;
i = 0;
lineadrs = malloc(sizeof(void) * 1024);
while ( fgets ( lineadrs, sizeof line, file ) != NULL ) /* read a line */
{
lineArray[i] = lineadrs;
lineadrs = malloc(sizeof(void) * 1024);
i++;
}
fclose ( file );
}
else {
perror ( filename );
return 0;
}
return lineArray ;
}
void swap(void *v[], int i, int j)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j]=temp;
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
if ( *(char*)first_arg < *(char*)second_arg )
{
return -1;
}
if ( *(char*)first_arg == *(char*)second_arg )
{
return 0;
}
else {
return 1;
}
}
//reverse the compare
int cmp2 (void * a, void * b)
{
char *ia = (char *)a; // casting pointer types
char *ib = (char *)b;
return *ib - *ia;
//return ( *(int *)b + *(int *)a );
}
void QSort(void *v[],int left, int right, int (*compare)(void *first, void *second))
{
int i, last;
void swap (void *v[],int ,int);
if(left >= right){
return;
}
swap(v,left,(left+right)/2);
last=left;
for(i=left+1;i<=right; i++){
if((*compare)(v[i],v[left])<0){
swap(v,++last,i);
}
}
swap(v,left,last);
QSort(v,left,last-1,compare);
QSort(v,last+1,right,compare);
}
int main(){
void * var[6];
readData(var);
printf("Original String:\n");
show(var);
QSort(var,0,4,cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var);
QSort(var,0,4,cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var);
return 0;
}
The list of things wrong in this code is almost too numerous to mention
the line array is fixed. it should be dynamic. reading more than 4 lines of text will invoke undefined behavior by exceeding your input array length
the comparators are wrong for string content.
the memory leaks are numerous.
The code below is, I believe, what you're trying to do. I sincerely hope you take the time to learn from it. There are still several things that should be done, but the difference is night and day already. And I should warn you I wrote this online and have given no test-time to it, but it should be correct. Since I have no example data from you, this is the extent of what I can do. I wish you the best of luck.
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// read data from a named file one line at a time, storing each
// in a ever-expanding line array. The return result is the
// number of lines allocated. The resulting line array is passed
// as an output parameter
int readData(const char filename[], void ***results)
{
// default answer: no lines, zero-length
void **lines = NULL;
int i=0;
FILE *file = fopen ( filename, "r" );
if ( file != NULL )
{
char line [ 128 ];
while ( fgets ( line, sizeof line, file ) != NULL )
{
// trim the newline from line buffer
size_t slen = strlen(line);
if (slen > 0 && line[slen-1] == '\n')
line[--slen] = 0;
// resize lines array
void **new_lines = realloc(lines, (i+1)*sizeof(*new_lines));
if (new_lines == NULL)
{
perror("Failed to realloc lines array.");
exit(EXIT_FAILURE);
}
// save new line entry, terminate with NULL;
lines = new_lines;
lines[i++] = strdup(line);
}
fclose ( file );
}
else
{
perror(filename);
exit(EXIT_FAILURE);
}
// setup output result and return value
*results = lines;
return i;
}
// display an array of a specified length
void show(void *array[], int len)
{
int i=0;
for (; i<len; ++i)
printf("String %d : %s\n", i, array[i]);
printf("\n");
}
//normal compare
int cmp1 (void *first_arg, void *second_arg)
{
return strcmp((const char*)first_arg, (const char*)second_arg);
}
//reverse the compare
int cmp2 (void *first_arg, void *second_arg)
{
return strcmp((const char*)second_arg, (const char*)first_arg);
}
// swap to void* by address
void swap(void **lhs, void **rhs)
{
void *tmp = *lhs;
*lhs = *rhs;
*rhs = tmp;
}
// the simplest quicksort I can fathom
void QSort(void *v[], int len, int (*compare)(void*, void*))
{
if (len < 2)
return;
// swap random element to last slot
swap(v+(rand() % len), v+(len-1));
// partition around the pivot value
int pvt=0,i;
for (i=0; i<len; ++i)
{
if (compare(v[i], v[len-1]) < 0)
swap(v+i, v+pvt++);
}
// swap pivot into place
swap(v+pvt, v+(len-1));
// recurse. note the pivot slot is skipped.
QSort(v, pvt++, compare);
QSort(v+pvt, len-pvt, compare);
}
int main()
{
static const char filename[] = "sampledata.txt";
srand((unsigned)time(NULL));
void **var = NULL;
int len = readData(filename, &var);
if (len > 0)
{
printf("Original String:\n");
show(var, len);
QSort(var, len, cmp1);
printf("After cmp 1 which compares alphabetically.\n");
show(var, len);
QSort(var, len, cmp2);
printf("After cmp 2 which compares reverse alphabetically.\n");
show(var, len);
// release lines when finished
while (len-- != 0)
free(var[len]);
free(var);
}
return 0;
}

Resources