Currently trying to work on my C (very new to it) by doing some leetcode questions. I'm puzzled by this issue, as it gives me a heap buffer overflow but only because of a single line. interpret()
is called and passed a string command
where 1 <= command.length <= 100
, and will consist of "G"
, "()"
, and/or "(al)"
in some order, with no other characters appearing.
char * interpret(char * command){
char * ret = malloc(sizeof(char) * 100);
int counter = 0;
for(int i = 0; i < sizeof(command) - 1; i )
{
if(command[i] == 'G')
{
ret[counter] = 'G';
counter ;
}
else if(command[i] == '(')
{
if (command[i 1] == ')')
{
ret[counter] = 'o';
counter ;
}
else
{
//ret[counter] = 'a'; ***********
ret[counter 1] = 'l';
counter = 2;
}
}
ret[counter] = '\0';
}
return realloc(ret, counter * sizeof(char));
}
If the starred line is uncommented, then the entire program crashes in leetcode, but works fine on VSCode and returns the correct solution. I would appreciate any help, I'm sure it's something small I'm missing. Thanks.
ETA: Here is the leetcode problem in question
CodePudding user response:
The parameter command
has the pointer type char *
.
So the operator sizeof
applied to the pointer yields the size of the pointer instead of the length of the pointed string
for(int i = 0; i < sizeof(command) - 1; i )
You could just write
for( size_t i = 0; command[i] != '\0'; i )
Also it is unclear why there is used the magic number 100
char * ret = malloc(sizeof(char) * 100);
You could at first count the result characters and then allocated an array of the appropriate size and fill it.
Moreover due to this statement
ret[counter] = '\0';
(that is also unclear why it is within the for loop) you need to allocate an array with counter 1
characters instead of counter
characters as you are doing
return realloc(ret, counter * sizeof(char));
A straightforward approach can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * interpret( const char *command )
{
size_t n = 0;
for ( size_t i = 0; command[i] != '\0'; )
{
if ( command[i] == 'G' )
{
n;
i;
}
else if ( strncmp( command i, "()", 2 ) == 0 )
{
n;
i = 2;
}
else if ( strncmp( command i, "(al)", 4 ) == 0 )
{
n = 2;
i = 4;
}
else
{
i;
}
}
char *result = malloc( n 1 );
if ( result != NULL )
{
n = 0;
for ( size_t i = 0; command[i] != '\0'; )
{
if ( command[i] == 'G' )
{
result[n ] = 'G';
i;
}
else if ( strncmp( command i, "()", 2 ) == 0 )
{
result[n ] = 'o';
i = 2;
}
else if ( strncmp( command i, "(al)", 4 ) == 0 )
{
result[n ] = 'a';
result[n ] = 'l';
i = 4;
}
else
{
i;
}
}
result[n] = '\0';
}
return result;
}
int main( void )
{
char *s = interpret( "G()(al)" );
if ( s ) puts( s );
free( s );
s = interpret( "(al)G(al)()()G" );
if ( s ) puts( s );
free( s );
}
The program output is
Goal
alGalooG
CodePudding user response:
Pass the size of command to interpret.
In C, when you pass a string to a function, you’re not actually passing the full string, you’re passing a pointer to the first element in the string. This becomes an issue when you do sizeof(command), as you're just getting the size of the pointer and not the full string. If you try to loop over this string as done in the question, this can either lead to an underread, if you have a string longer than sizeof(char*)
, or a buffer overflow, if you have a string shorter than sizeof(char*)
. Generally, you shouldn’t use sizeof on pointers.
To fix your code, use strlen
on the string you're passing to command
in the calling function and do something similar to this:
char * interpret(char * command, int size){
char * ret = malloc(sizeof(char) * 100);
int counter = 0;
for(int i = 0; i < size; i )
{ ...