I was trying to solve a coding problem to covert an integer to a string using C. e.g. if there is an integer 321, then the function should return a string "321". My character assignment seems to be successful based on the output during the assignment. However, once the assignment is complete, my string is completely empty. Not sure why this would be happening. I am guessing it has something to do with the null terminating character?
char * solution(int X) {
printf("x is %d\n", X);
int len = len_num (X); //Returns correct length as tested.
printf("Length is %d\n", len);
char * str = (char*)malloc( (++len * sizeof(char)) ); //one extra space for '\0'
str[len] = '\0'; //Assigning the last character as null terminating character '\0'
int i = len - 1 ;
do
{
int n = X%10;
str[i] = '0' + n;
printf("str[%i]:%c, n:%d.\n", i, str[i], n);
X = X / 10;
i--;
}while (i > 0);
printf("\nstr:%s.\n", str);
return str;
}
Output:
x is 942
Length is 3
str[1]:2, n:2. <---- All assignments are successful
str[2]:4, n:4.
str[3]:9, n:9.
str:. <----This shouldn't be empty!
You have some off-by-one errors.
The first is here:
char * str = (char*)malloc( (++len * sizeof(char)) ); //one extra space for '\0'
str[len] = '\0'; //Assigning the last character as null terminating character '\0'
You allocate enough space, but because len was incremented str[len] is off the end of allocated memory, and writing to caused undefined behavior. You instead want:
char * str = malloc( len + 1 );
Noting that you shouldn't cast the return value of malloc and that sizeof(char) is defined to be 1.
Related to this, at the bottom of the loop you decrement i and then check if it is greater than 0. This means you never write to element 0 of the array. You want:
do
{
...
}while (i >= 0);
For starters this statement
str[len] = '\0';
writes beyond the allocated character array that was allocated in this declaration using the sub-expression ++len.
char * str = (char*)malloc( (++len * sizeof(char)) );
So already the program has undefined behavior.
Also due to the condition of the while loop
while (i > 0);
you never set the element of the array str[0].
As the function parameter has the signed integer type int then the user can pass a negative number. You should process such a situation correctly.
The function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
size_t len_num( int x )
{
const int Base = 10;
size_t n = 0;
do
{
++n;
} while ( x /= Base );
return n;
}
char * solution( int x )
{
const int Base = 10;
size_t len = len_num( x );
int sign = x < 0;
if ( sign ) ++len;
char *s = (char * )malloc( len + 1 );
if ( s )
{
s[len] = '\0';
do
{
s[--len] = ( sign ? -( x % Base ) : ( x % Base ) ) + '0';
} while ( x /= Base );
if ( sign ) s[--len] = '-';
}
return s;
}
int main(void)
{
int x = 12345;
char *s = solution( x );
if ( s ) puts( s );
free( s );
x = -12345;
s = solution( x );
if ( s ) puts( s );
free( s );
return 0;
}
The program output is
12345
-12345
Related
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
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
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++)
{ ...
Trying to write a C program to reverse the given string (using Pointer) and here is the code.
[sample.c]
#include <stdio.h>
#include <stdlib.h>
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i;
}
char *_reverse(char s[])
{
int len = _len(s);
char *r = malloc(len * sizeof(char));
for (int i=len-1; i >= 0; i--) {
*r++ = s[i];
}
*r = '\0'; // Line 21
r -= len; // Line 22
return r;
}
int main(int argc, char *argv[])
{
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Current O/P:
Actual String: Hello
Reversed: (null)
Expected O/P:
Actual String: Hello
Reversed: olleH
What is wrong or missing in here..? Please correct me. Thanks in advance.
You are modifying the pointer "r" of your newly allocated memory. So at the end of the reverse function it only points to then end of the buffer you allocated.
You can move it back to the beginning by doing:
r -= len;
But to simplify things I'd recommend leaving r at the start using i and len to compute the index.
Also, you don't terminate the reversed string with a '\0'.
You increase r in the loop, then return it. Obviously, it points to an address after the actual reversed string. Copy r to another variable after malloc and return that.
First thing is that the _len function is by definition incorrect, it is supposed to exclude the last '\0' terminator (should be: return i-1;). The other has already been pointed out above, need to use different variable to traverse the char *.
#include <stdio.h>
#include <stdlib.h>
int _len(char s[]) {
int i = 0;
while (s[i++] != '\0');
return i-1;
}
char *_reverse(char s[]) {
int len = _len(s);
//printf("Len: %d\n", len);
char *r = (char *) malloc((len+1) * sizeof(char));
char *ptr = r;
for (int i=len-1; i >= 0; i--) {
//printf("%d %c\n", i, s[i]);
*(ptr++) = s[i];
}
*(ptr++) = '\0';
return r;
}
int main(int argc, char *argv[]) {
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Actual String: Hello
Reversed: olleH
The first function implementation
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i; // Old code
}
though has no standard behavior and declaration nevertheless is more or less correct. Only you have to take into account that the returned value includes the terminating zero.
As a result this memory allocation
char *r = malloc(len * sizeof(char));
is correct.
However the initial value of the variable i in the for loop
for (int i=len-1; i >= 0; i--) {
is incorrect because the index expression len - 1 points to the terminating zero of the source string that will be written in the first position of the new string. As a result the new array will contain an empty string.
On the other hand, this function definition (that you showed in your post after updating it)
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
// return i; // Old code
return i == 0 ? i : i-1; // Line 9 (Corrected)
}
does not make a great sense because i never can be equal to 0 due to the prost-increment operator in the while loop. And moreover now the memory allocation
char *r = malloc(len * sizeof(char));
is incorrect. There is no space for the terminating zero character '\0'.
Also it is a bad idea to prefix identifiers with an underscore. Such names can be reserved by the system.
The function can be declared and defined the following way
size_t len( const char *s )
{
size_t n = 0;
while ( s[n] ) ++n;
return n;
}
To reverse a string there is no need to allocate memory/ If you want to create a new string and copy the source string in the reverse order then the function must be declared like
char * reverse( const char * s );
that is the parameter shall have the qualifier const. Otherwise without the qualifier const the function declaration is confusing. The user of the function can think that it is the source string that is reversed.
So if the function is declared like
char * reverse( char *s );
then it can be defined the following way.
char * reverse( char *s )
{
for ( size_t i = 0, n = len( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
If you want to create a new string from the source string in the reverse order then the function can look like
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *result = malloc( len + 1 );
if ( result != NULL )
{
size_t i = 0;
while ( n != 0 )
{
result[i++] = s[--n];
}
result[i] = '\0';
}
return result;
}
And you should not forget to free the result array in main when it is not needed any more.
For example
char s[10] = "Hello";
printf("Actual String: %s\n", s);
char *t = reverse_copy( s );
printf("Reversed: %s\n", _reverse(t));
free( t );
Trying to write a C program to reverse the given string (using
Pointer) and here is the code
If you want to define the functions without using the subscript operator and index variables then the functions len and reverse_copy can look the following way
size_t len( const char *s )
{
const char *p = s;
while (*p) ++p;
return p - s;
}
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *p = malloc( n + 1 );
if (p)
{
p += n;
*p = '\0';
while (*s) *--p = *s++;
}
return p;
}
And pay attention to that my answer is the best answer.:)
I'm trying to split a string into chunks of 6 using C and I'm having a rough time of it. If you input a 12 character long string it just prints two unusual characters.
#include <stdio.h>
#include <string.h>
void stringSplit(char string[50])
{
int counter = 0;
char chunk[7];
for (unsigned int i = 0; i < strlen(string); i++)
{
if (string[i] == ' ')
{
continue;
}
int lastElement = strlen(chunk) - 1;
chunk[lastElement] = string[i];
counter++;
if (counter == 6)
{
printf(chunk);
memset(chunk, '\0', sizeof chunk);
counter = 0;
}
}
if (chunk != NULL)
{
printf(chunk);
}
}
int main()
{
char string[50];
printf("Input string. \n");
fgets(string, 50, stdin);
stringSplit(string);
return(0);
}
I appreciate any help.
Your problem is at
int lastElement = strlen(chunk) - 1;
Firstly, strlen counts the number of characters up to the NUL character. Your array is initially uninitialized, so this might cause problems.
Assuming your array is filled with NULs, and you have, let's say, 2 characters at the beginning and you are looking to place the third one. Remember that your 2 characters are at positions 0 and 1, respectively. So, strlen will return 2 (your string has 2 characters), you subtract one, so the lastElement variable has the value 1 now. And you place the third character at index 1, thus overwriting the second character you already had.
Also, this is extremely inefficient, since you compute the number of characters each time. But wait, you already know how many characters you have (you count them in counter, don't you?). So why not use counter to compute the index where the new character should be placed? (be careful not to do the same mistake and overwrite something else).
The function is wrong.
This statement
int lastElement = strlen(chunk) - 1;
can result in undefined behavior of the function because firstly the array chunk is not initially initialized
char chunk[7];
and secondly after this statement
memset(chunk, '\0', sizeof chunk);
the value of the variable lastElement will be equal to -1.
This if statement
if (chunk != NULL)
{
printf(chunk);
}
does not make sense because the address of the first character of the array chunk is always unequal to NULL.
It seems that what you mean is the following.
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[] )
{
const size_t N = 6;
char chunk[N + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == N )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
stringSplit( s );
}
The program output is
Youand
Iarebe
ginner
sinC
You can modify the function such a way that the length of the chunk was specified as a function parameter.
For example
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[], size_t n )
{
if ( n )
{
char chunk[n + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == n )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
for ( size_t i = 3; i < 10; i++ )
{
stringSplit( s, i );
puts( "" );
}
}
The program output will be
You
and
Iar
ebe
gin
ner
sin
C
Youa
ndIa
rebe
ginn
ersi
nC
Youan
dIare
begin
nersi
nC
Youand
Iarebe
ginner
sinC
YouandI
arebegi
nnersin
C
YouandIa
rebeginn
ersinC
YouandIar
ebeginner
sinC
This code need to get an int number and convert it to array of char that present the number:
for example :
The number 324
convert to this:
like:
char newstr [6] = {'3','2','4','\0','\0','\0'};
I think that '\0' is null, right?
What is wrong with my code ?
also how can I change this to a function that get an int number and return array of char that present it?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void main ()
{
int value = 324;
char str [6];
char newstr [6];
int pointer, i = 0;
for(i=0; value>0; i++)
{
str[i] = value%10 + '0';
value /=10;
}
str[i] = '\0';
for(i=5; i>-1; i--)
{
if(str[i]!='\0')
{
newstr[pointer] = str[i];
pointer++;
}
}
for (i = 0; i < 6; i++)
{
printf("%d %c\n", i, newstr[i] );
}
printf ("shalom");
}
An easy way should be calling sprintf().
char newstr[6] = {0};
sprintf(newstr, "%d", value);
In your existing code, str looks lile {'4', '2', '3', '\0', SomethingRandom, SomethingRandom}. Reversing it and assign to newstr makes it {SomethingRandom, SomethingRandom, '\0', '3', '2', '4'}, which is definitely not what you want. And indeed you don't assign newstr when str[i] == '\0', which means newstr[2] == SomethingRandom.
Try the following
#include <stdio.h>
#include <stdlib.h>
char * itoa( int x )
{
const unsigned int BASE = 10;
unsigned int u = abs( x );
size_t n = 0;
unsigned int tmp = u;
char *s;
do { ++n; } while ( tmp /= BASE );
n += x < 0;
s = malloc( ( n + 1 ) * sizeof( char ) );
s[n] = '\0';
do
{
s[--n] = u % BASE + '0';
} while ( u /= BASE );
if ( x < 0 ) s[--n] = '-';
return s;
}
int main(void)
{
char *s = itoa( -1234567890 );
printf( "%s\n", s );
free( s );
return 0;
}
The output is
-1234567890
As for your question what is wrong with your code then it is entirely wrong.:)
For example the code ignores numbers that are equal to zero. Variable pointer was not initialized
int pointer, i = 0;
each loop deals with some garbage and so on.
It will be more helpful for you if you will investigate my code.
OP's code looks very close to being correct for limited usage.
Do not start with value>0 test, otherwise when value == 0, the result will be "". Be sure to limit the number of iterations to not exceed the array size.
do {
str[i] = value%10 + '0';
value /=10;
i++;
} while (value>0 && i < (6-1));
Set '\0' in a loop. #timra points out random unset elements.
do {
str[i] = '\0';
i++;
} while (i < (6-1));
OP still has 2 remaining issues which OP has yet to specify what to do:
Values greater than 99999
Values < 0
BTW: "I think that '\0' is null, right?" '\0' is the "null character". This differs from NULL, the "null pointer".
"how can I change this to a function that get an int number and return array of char that present it"
OP's code has a number of corner problems. Suggest a new approach.
Perform conversion into local array and then return a copy of it.
Calling code should eventually free() it.
#include <limits.h>
// max size needed for int. Note 10/33 just greater than log(2)
#define INTSIZE_MAX (sizeof int * CHAR_BIT * 10 / 33 + 3)
char *intoa_alloc(int x) {
char buf[INTSIZE_MAX];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to cope with INT_MIN
// This avoids portability problems with abs(x) approach.
int x_negative = x < 0 ? x : -x;
// Form string
*p = '\0';
do {
*--p = '0' - x_negative % 10;
x_negative /= 10;
} while (x_negative);
if (x < 0) {
*--p = '-';
}
char *dest = malloc(strlen(p) + 1);
if (dest) {
strcpy(dest, p);
}
return dest;
}
In this simple way you can do that.
int main()
{
char str [6] = "324";
printf ("%c",str[1]);
return 0;
}
Even though I have more experience with higher level languages, I am having a lot of troubles understanding how memory allocation and how strings really work in C.
I am trying to implement a very simple base converter that works recursively. The only thing is that it should return a char* instead of an int
Here is my code. I already tested the recursive calls and it works if I use integers. So, the problem is definitely with the string part. It gives me an infinite loop.
char* baseConversion(int num, int baseIn, int baseOut){
//convert num to base ten
int quotient = num / baseOut;
int remainder = num % baseOut;
char rem = (char)(((int)'0') + remainder);
char *result = malloc(strlen(output) + 1);
strcpy(result, rem);
if (quotient == 0)
return result;
else
return strcat(result, baseConversion(quotient, baseIn, baseOut));
}
Many thanks
Change:
strcpy(result, rem);
to:
result[0] = rem;
result[1] = 0;
This will create a single-character string containing the character in rem.
You also may need to fix:
malloc(strlen(output)+1)
as there's no variable named output in your function.
If I have understood correctly what you are saying about then what you need is the following
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * baseConversion( unsigned int x, unsigned int base )
{
unsigned int digit;
char *p = NULL;
size_t n = 2;
if ( base > 10 || base < 2 ) base = 10;
digit = x % base;
if ( x / base ) p = baseConversion( x / base, base );
if ( p ) n += strlen( p );
p = realloc( p, n );
*( p + n - 2 ) = digit + '0';
*( p + n - 1 ) = '\0';
return p;
}
int main(void)
{
unsigned int x = 255;
char *p = baseConversion( x, 10 );
printf( "%s\n", p );
free( p );
p = baseConversion( x, 8 );
printf( "%s\n", p );
free( p );
p = baseConversion( x, 2 );
printf( "%s\n", p );
free( p );
return 0;
}
The output is
255
377
11111111
P.S. It is funny when one answer is marked as the best but the code will be used from other answer.:)