Segmentation fault in postfix to infix C code - c

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);
}

Related

How to fix? Triggers exception when trying to free dynamic allocated memory

This is my first time posting question, and I did try to find solution, but, even if I did found it I didn't recognize it.
So, as the title says, the problem is in this triggered exception "Exception thrown at 0x0F26372D (ucrtbased.dll) in lab10.exe: 0xC0000005: Access violation reading location 0xCCCCCCC4.
If there is a handler for this exception, the program may be safely continued.", which happens when I step into line -> free(word).
This did happen to me a few times when I was learning malloc, but I overlooked it - thinking there was some other problem. But now I see that I'am doing something wrong.
The point of the program is - writing the struct "word". I need to input sentence and "cut" it into words, and then every word put in struct together with size of letters in the word and ordinal number of the word.
#include <stdio.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
void cutting_sentence(struct word *p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
p = (struct word*)malloc(size_sen * sizeof(struct word));
if (p == NULL) {
printf("\nNot enaugh memory!");
return 0;
}
strcpy(p[0].text_word, strtok(sen, " ,.!?"));
p[0].sizee = strlen(p[0].text_word);
p[0].number = 1;
printf("word:%s \t size:%u \t ordinal number of the word:%u\n",
p[0].text_word, p[0].sizee, p[0].number);
for (i = p[0].sizee - 1, j = 1;i < size_sen;++i) {
if (*(sen + i) == ' ' || *(sen + i) == '.' || *(sen + i) == ','
|| *(sen + i) == '?' || *(sen + i) == '!') {
strcpy(p[j].text_word, strtok(NULL, " ,.!?"));
p[j].sizee = strlen(p[j].text_word);
p[j].number = j + 1;
printf("word:%s \t size:%u \t ordinal number of the
word:%u\n", p[j].text_word, p[j].sizee, p[j].number);
j++;
}
}
}
int main() {
char sentence[1024];
struct word *word;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&word, sentence);
free(word); //here is exception triggered
return 0;
}
You're changing the local value of the pointer argument passed, you need to change the memory at its target for the caller to discover the location of the allocated memory. Since you didn't do that, you're trying to free the local variable word which is stored on the stack of main().
First thing to fix is not to have a variable identical to the name of a type, that's just evil.
Then change the function prototype to pass a double pointer:
void cutting_sentence(struct word **p, char *sen);
And remember that where you were using p you now need to use *p or first assign a local (word *) with the address value contained there.
void cutting_sentence(struct word **p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
*p = (struct word*)malloc(size_sen * sizeof(struct word));
if (*p == NULL) {
printf("\nNot enaugh memory!");
return; //void cannot return a value
}
and so on changing every usage of p to *p.
and then
int main() {
char sentence[1024];
struct word *words;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&words, sentence);
if (words != NULL)
free(words); //now valid
return 0;
}
There are a few more issues than those previously discussed.
[As already pointed out] your first argument should be struct word **. But, a simpler way is to eliminate it and change the return type to struct word *. This allows the code within the function to be simpler (i.e. no double dereferencing of a pointer)
Although allocating as many word structs as there are characters in the input string will work, that is somewhat unusual.
A better way [more idiomatic, at least] to do this is to use realloc inside the loop.
In either case, the array size can be trimmed to only use what it needs via a final realloc.
I think that your loop that scans sen looking for delimiters is overly complex. Simply using strtok in the loop will give the same effect with less complexity.
Also, you're not conveying back a count of the number of word. One way is to add an extra element to the array that has a size of zero (e.g. an end-of-list marker)
Here's is a refactored version that should help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; // number of letters of the word
unsigned number; // ordinal number of the word
};
struct word *
cutting_sentence(char *sen)
{ // sen is sentence
int curcnt = 0;
int maxcnt = 0;
char *token;
struct word *word;
struct word *words;
while (1) {
token = strtok(sen," ,.!?\n");
if (token == NULL)
break;
sen = NULL;
if (curcnt >= maxcnt) {
maxcnt += 100;
words = realloc(words,sizeof(struct word) * (maxcnt + 1));
}
word = &words[curcnt];
strcpy(word->text_word,token);
word->number = curcnt;
word->sizee = strlen(token);
++curcnt;
}
words = realloc(words,sizeof(struct word) * (curcnt + 1));
// set end-of-list
word = &words[curcnt];
word->sizee = 0;
return words;
}
int
main()
{
char sentence[1024];
struct word *words;
struct word *word;
printf("Sentence: ");
fflush(stdout);
fgets(sentence,sizeof(sentence),stdin);
words = cutting_sentence(sentence);
for (word = words; word->sizee != 0; ++word)
printf("main: number=%u sizee=%u text_word='%s'\n",
word->number,word->sizee,word->text_word);
free(words);
return 0;
}
the following proposed code:
eliminates redundant code
properly checks for errors
properly outputs error message (and the text reason the system thinks an error occurred to stderr
performs the desired functionality
properly initializes the struct word pointer
properly updates the struct word pointer
changed int sizee to size_t sizee because the function: strlen() returns a size_t, not an int
changed int i to unsigned i because the declaration of the struct field number is declared as unsigned
documents why each header file is included
allocates an instance of the struct word for every character in the sentence This is 'overkill'. The most possible amount of words would be if every word was only a single character. So, immediately, the size of the allocated memory could be cut in half. A loop, counting the word separators would result in the correct amount of allocated memory. You could easily add that feature.
Note the way that the function: strtok() is used. I.E. initial call before loop, then following calls at end of loop
And now the proposed code:
#include <stdio.h> // printf(), fgets(), NULL
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), free()
#include <string.h> // strlen(), strtok()
struct word
{
char text_word[50];
size_t sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
// notice the `**p` so can access the pointer in `main()` so it can be updated
void cutting_sentence(struct word **p, char *sen)
{ //sen is sentence
size_t size_sen = strlen(sen); //size of sentence
struct word *wordptr = *p;
wordptr = malloc(size_sen * sizeof(struct word));
if ( !wordptr )
{
perror("malloc failed");
exit( EXIT_FAILURE );
}
unsigned i = 0;
char * token = strtok(sen, " ,.!?");
while( token )
{
strcpy( wordptr[i].text_word, token );
wordptr[i].sizee = strlen( token );
wordptr[i].number = i;
printf("word:%s\t Length:%lu]tordinal number of the word:%u\n",
wordptr[i].text_word,
wordptr[i].sizee,
wordptr[i].number);
token = strtok( NULL, " ,.!?");
i++;
}
}
int main( void )
{
char sentence[1024];
struct word *wordArray = NULL;
printf("Sentence: ");
if( !fgets(sentence, sizeof( sentence ), stdin ) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// remove trailing new line
sentence[ strcspn( sentence, "\n") ] = '\0';
cutting_sentence(&wordArray, sentence);
free( wordArray ); //here is exception triggered
return 0;
}
A typical run of the code results in:
Sentence: hello my friend
word:hello Length:5 ordinal number of the word:0
word:my Length:2 ordinal number of the word:1
word:friend Length:6 ordinal number of the word:2
Notice that 'short' words result in an uneven output. You might want to correct that.

how can i use pointer to move inside of this array (function) instead of array subscribting

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)

Adding to an array in main via function argument

I'm not sure if I even worded the title correctly, but basically. I want to know if there is a way to add to the buff array from the hey function using the pointers in the arguments and why does it work if it does?
buf[100].
example:
int main(){
char buf[100];
hey("320244",buf);
printf("%s", buf);
}
void hey(char* s, char* result){
/*
some code that appends to result using pointers
do some stuff with s and get the result back in buf without using return.
*/
}
I have modified your code with some comments :-
#define LEN 100 //Use a macro instead of error prone digits in code
void hey(char* s, char* result); //Fwd declaration
int main(){
char buf[LEN] = {0}; //This will initialize the buffer on stack
hey("320244",buf);
printf("%s", buf);
hey("abc", buf); //Possible future invocation
printf("%s", buf);
}
void hey(char* s, char* result){
if(strlen(result) + strlen(s) < LEN ) //This will check buffer overflow
strcat(result, s); //This will concatenate s into result
else
//Do some error handling here
}
Let's do the right thing, and use a structure to describe a dynamically allocated, grow-as-needed string:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct mystring {
char *ptr; /* The actual string */
size_t len; /* The length of the string */
size_t max; /* Maximum number of chars allocated for */
};
#define MYSTRING_INIT { NULL, 0, 0 }
If we want to append something to a struct mystring, we define a function that takes a pointer to the structure the function can modify. (If it only needed a char pointer instead of a structure, it'd take a char **; a pointer to a char pointer.)
void mystring_append(struct mystring *ms, const char *s)
{
const size_t slen = (s) ? strlen(s) : 0;
/* Make sure ms points to a struct mystring; is not NULL */
if (!ms) {
fprintf(stderr, "mystring_append(): No struct mystring specified; ms == NULL!\n");
exit(EXIT_FAILURE);
}
/* Make sure we have enough memory allocated for the data */
if (ms->len + slen >= ms->max) {
const size_t max = ms->len + slen + 1;
char *ptr;
ptr = realloc(ms->ptr, max);
if (!ptr) {
fprintf(stderr, "mystring_append(): Out of memory!\n");
exit(EXIT_FAILURE);
}
ms->max = max;
ms->ptr = ptr;
}
/* Append. */
if (slen > 0) {
memmove(ms->ptr + ms->len, s, slen);
ms->len += slen;
}
/* We allocated one char extra for the
string-terminating nul byte, '\0'. */
ms->ptr[ms->len] = '\0';
/* Done! */
}
The (s) ? strlen(s) : 0; expression uses the ?: conditional operator. Essentially, if s is non-NULL, the expression evaluates to strlen(s), otherwise it evaluates to 0. You could use
size_t slen;
if (s != NULL)
slen = strlen(s);
else
slen = 0;
instead; I just like the concise const size_t slen = (s) ? strlen(s) : 0 form better. (The const tells the compiler that the slen variable is not going to be modified. While it might help the compiler generate better code, it is mostly a hint to other programmers that slen will have this particular value all through this function, so they do not need to check if it might be modified somewhere. It helps code maintenance in the long term, so it is a very good habit to get into.)
Normally, functions return success or error. For ease of use, mystring_append() does not return anything. If there is an error, it prints an error message to standard output, and stops the program.
It is a good practice to create a function that releases any dynamic memory used by such a structure. For example,
void mystring_free(struct mystring *ms)
{
if (ms) {
free(ms->ptr);
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
}
Often, you see initialization functions as well, like
void mystring_init(struct mystring *ms)
{
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
but I prefer initialization macros like MYSTRING_INIT, defined earlier.
You can use the above in a program like this:
int main(void)
{
struct mystring message = MYSTRING_INIT;
mystring_append(&message, "Hello, ");
mystring_append(&message, "world!");
printf("message = '%s'.\n", message.ptr);
mystring_free(&message);
return EXIT_SUCCESS;
}
Notes:
When we declare a variable of the structure type (and not as a pointer to the structure, i.e. no *), we use . between the variable name and the field name. In main(), we have struct mystring message;, so we use message.ptr to refer to the char pointer in the message structure.
When we declare a variable as a pointer to a structure type (as in the functions, with * before the variable name), we use -> between the variable name and the field name. For example, in mystring_append() we have struct mystring *ms, so we use ms->ptr to refer to the char pointer in the structure pointed to by the ms variable.
Dynamic memory management is not difficult. realloc(NULL, size) is equivalent to malloc(size), and free(NULL) is safe (does nothing).
In the above function, we just need to keep track of both current length, and the number of chars allocated for the dynamic buffer pointed to by field ptr, and remember that a string needs that terminating nul byte, '\0', which is not counted in its length.
The above function reallocates only just enough memory for the additional string. In practice, extra memory is often allocated, so that the number of reallocations needed is kept to a minimum. (This is because memory allocation/reallocation functions are considered expensive, or slow, compared to other operations.) That is a topic for another occasion, though.
If we want a function to be able to modify a variable (be that any type, even a structure) in the callers scope -- struct mystring message; in main() in the above example --, the function needs to take a pointer to variable of that type, and modify the value via the pointer.
The address-of operator, &, takes the address of some variable. In particular, &message in the above example evaluates to a pointer to a struct mystring.
If we write struct mystring *ref = &message;, with struct mystring message;, then message is a variable of struct mystring type, and ref is a pointer to message; ref being of struct mystring * type.
If I have understood you correctly you mean the following
#include <string.h>
//...
void hey(char* s, char* result)
{
strcpy( result, s );
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
void hey( const char* s, char* result);
int main(void)
{
char buf[100];
hey( "320244", buf );
printf( "%s\n", buf );
return 0;
}
void hey( const char* s, char* result )
{
strcpy( result, s );
}
Its output is
320244
If the array buf already stores a string then you can append to it a new string. For example
#include <string.h>
//...
char buf[100] = "ABC";
strcat( buf, "320244" );
Take into account that the function hey should be declared before its usage and according to the C Standard the function main shall be declared like
int main( void )

return pointer from a function in c

Write function that gets a string s and char c that checks whether the char shows in s, if yes return a pointer to the first place that c shows in s
Here is my code. I am not sure what I did about "return the pointer", is this correct?:
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
char *ptr;
for(i=0;s[i];i++)
{
if(s[i]==c)
{
printf("result: %d",i);
*ptr=i;
return ptr;
}
}
}
void main()
{
char s[]="Error404";// some string
char c='r';// some char
foo(s,c);
}
First of all, your specification is unclear. Before you start coding, make sure that the specification makes sense. It doesn't say what to do if you don't find the character, so you can't write this function before you know that.
Your function must always return something, even if the character was not found. A common way to implement this would be to return a null pointer in that case.
Your pointer should point at the found character, not at i which is an integer, that doesn't make any sense.
Correct the code into something like this:
char* foo (char s[], char c)
{
char *ptr = NULL;
for(int i=0; s[i]!='\0'; i++)
{
if(s[i]==c)
{
ptr = &s[i]; // point at the address of item number i in s
break;
}
}
return ptr; // will return NULL if not found, otherwise a pointer to the found item
}
If s is a string, then s[i] represents the ith char in the string, while s + i represents a pointer to the ith char in the string. So you want to return s + i. You probably also want to return NULL if the char is not found.
#include <stdio.h>
char *foo(char s[], char c)
{
int i;
for(i = 0; s[i]; i++)
{
if(s[i] == c)
return (s + i);
}
return (NULL);
}

How to replace the last index of a string using C language?

The code below tries to increment the last index in a string, eg: if label = "1_1_9", find_next_label (label ) will return "1_1_10".
This works. However, I also want to alter the original label, increment it as well. eg: if label = "1_1_9", find_next_label(label) will return "1_1_10" and during this procedure, label also becomes "1_1_10".
This code below is unable to do this. The result from main() function shows that label is still "1_1_9".
Could anyone help find where the problem is?
char * find_next_lable(char * label)
{
int length = strlen(label);
char * last_index = label + length - 1;
int num = atoi(last_index);
num = num + 1;
char * next_lable = malloc(sizeof(label));
strncpy(next_label, label, length-1);
*(next_label + length - 1) = '\0';
sprintf(next_label, "%s%d", next_label, num);
label = next_label;
return label;
}
int main()
{
char * s = malloc(6);
strcpy(s, "1_1_9");
char * n = find_next_label(s);
printf("%s\n", s);
printf("%s\n", n);
return 0;
}
The last_index() and atoi() code block assumes that the final number is only one digit long; clearly this is not very general. You could search for the last underscore instead, and convert a number from the character following that. Use strrchr() to look for the last underscore.
Also you must think a lot about buffer sizes and overruns, you should probably make the function accept the available buffer size as an additional argument especially if you want to modify the input. If you want that, there's of course no point in allocating additional space either, just return the input.
If you don't need to create a new string you can just do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 20
int main()
{
char *s = malloc(MAX_LEN); /* You must have enough memory if the number of chars grows! */
char *n;
int i;
strcpy(s, "1_1_9");
printf("%s\n", s);
n = strrchr(s, '_'); /* find the last '_' */
n++; /* and move to the number */
i = atoi(n);
sprintf(n, "%d", i+1); /* write the new value instead of the old one */
printf("%s\n", s);
free(s);
return 0;
}
else you can have the function:
char * find_next_lable(char *label)
{
char *n, *next_lable = malloc(sizeof(MAX_LEN));
int i;
strcpy(next_lable, label);
n = strrchr(next_lable, '_');
n++;
i = atoi(n);
sprintf(n, "%d", i+1);
return next_lable;
}
The result from main() function shows that lable is still 1_1_9.
That's because you are not changing the dynamically allocated array pointed to by s in main. Instead, you allocate new memory in the function find_next_lable. Also,
sprintf(next_lable, "%s%d", next_lable, num);
won't work since %s conversion specifier means that sprintf will read from the buffer pointed to by next_lable till and including the terminating null byte.
You must allocate enough memory so as to contain the incremented integer part.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// make sure MAX is large enough to
// contain the modified string
#define MAX 20
void find_next_lable(char *label);
int main(void)
{
char *s = malloc(MAX);
strcpy(s, "1_1_90");
printf("%s\n", s);
find_next_lable(s);
printf("%s\n", s); // prints 1_1_91
free(s);
return 0;
}
void find_next_lable(char *label)
{
// strrchr returns a pointer to the last
// occurrence of the character _ in label
char *last_index = strrchr(label, '_');
if(last_index == NULL)
{
last_index = label;
}
else
{
last_index++;
}
int num = atoi(last_index);
num = num + 1;
sprintf(last_index, "%d", num);
}

Resources