C - invalid read of size 1 - c

ok that's it, it's been more than 15 hours and i still can't figure out what's going on !
Here is a code for timeconversion problem in hackerrank, a function takes a string (time in 12--hour AM/PM format) and converts it to military (24-hour) time (returning a string)
the problem is exactly in the function char* timeConversion(char* s)
in this line of code
b = strcmp(ampm,"PM");
it always gives me error which i can not understand
"ERROR: invalid read of size 1"
can anyone help me ?!
#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* readline();
/*
* Complete the timeConversion function below.
*/
/*
* Please either make the string static or allocate on the heap. For example,
* static char str[] = "hello world";
* return str;
*
* OR
*
* char* str = "hello world";
* return str;
*
*/
/* Swaps strings by swapping pointers */
void swap(char **str1_ptr, char **str2_ptr)
{
char *temp = *str1_ptr;
*str1_ptr = *str2_ptr;
*str2_ptr = temp;
}
void reverse(char str[], int length)
{
int start = 0;
int end = length -1;
while (start < end)
{
swap(*(str+start), *(str+end));
start++;
end--;
}
}
// Implementation of itoa()
char* itoa(int num, char* str, int base)
{
int i = 0;
bool isNegative = false;
/* Handle 0 explicitely, otherwise empty string is printed for 0 */
if (num == 0)
{
str[i++] = '0';
str[i] = '\0';
return str;
}
// In standard itoa(), negative numbers are handled only with
// base 10. Otherwise numbers are considered unsigned.
if (num < 0 && base == 10)
{
isNegative = true;
num = -num;
}
// Process individual digits
while (num != 0)
{
int rem = num % base;
str[i++] = (rem > 9)? (rem-10) + 'a' : rem + '0';
num = num/base;
}
// If number is negative, append '-'
if (isNegative)
str[i++] = '-';
str[i] = '\0'; // Append string terminator
// Reverse the string
reverse(str, i);
return str;
}
char* timeConversion(char* s) {
/*
* Write your code here.
*/
char *result = (char*)calloc(8,sizeof(char)) ;
char *ampm = (char*)calloc(2,sizeof(char)) ;
char *hh = (char*)calloc(2,sizeof(char)) ;
int a = 0, b = 0 ,c = 0,i;
long int dec = 0;
int len = strlen(s);
// substring hh:mm:ssAM
while ( c < 2) // 2 : LENGTH
{
ampm[c] = s[9+c-1]; // 9 : position
hh[c] = s[1+c-1]; // 1 : position
c++ ;
}
// string to int
//len = strlen(ampm);
for(i = 0; i < 2 ; i++)
{
dec = dec * 10 + (hh[i] - '0');
}
b = strcmp(ampm,"PM");
a = strcmp(ampm,"AM");
printf("%d\n",a);
printf("%d\n",b);
// processing
if (!strcmp(ampm,"AM") && dec==12) dec = 0;
if (!strcmp(ampm,"PM") && dec!=12) dec += 12;
//if (strcmp(s[9],'A') && dec==12) dec = 0;
//if (strcmp(s[9],'P') && dec!=12) dec += 12;
// convert int back to string
char* hhh = itoa(dec, hh, 10);
//dec = atol(hh);
// hh = itoa(dec,10);
// snprintf(result,9,"%d", dec);
//printf("%s\n",hh);
c = 0;
char* sub;
while (c < 9)
{
sub[c] = s[3+c-1];
c++ ;
}
strcat(result,hhh);
strcat(result,sub);
return result;
}
int main()
{
char *s = "07:05:45PM";
char* result = timeConversion(s);
printf("%s\n", result);
return 0;
}

Like the commenters mentioned, it seems like you are missing the NULL-termination, e.g.:
char *ampm = (char*)calloc(2,sizeof(char)) ;
Two characters ('am'/'pm') plus the NULL-Termination would be 3 characters, not 2.
You have to make sure that all your strings have a size of len + 1 and are properly '\0' terminated.

There are 4 issues in your code.
You are not allocating memory to NULL char for apmp
char *ampm = (char*)calloc(3,sizeof(char)) ;
You are receiving double pointer for swap function and passing char value
void swap(char **str1_ptr, char **str2_ptr)
should be
void swap(char *str1_ptr, char *str2_ptr)
and you call swap function like below
swap((str+start), (str+end));
You are not allocating memory to sub pointer
char* sub = malloc (9 * sizeof(char));
You are not deallocating memory for hh, sub and ampm.
free (hh); free(ampm); free(sub);

Related

How to modify a char pointer passed as parameter in a function?

So, I am doing my own rudimentary version of itoa(), and I just realized I don't exactly know how to modify a char* passed as parameter, or if there is something wrong with the way I am doing it...
The way I am doing it is by doing malloc() onto the buffer passed as argument, then write the number into it. This is apparently working before returning from the function (the buffer is printed correctly), but then when trying to print it back in main(), it segfaults.
If I understand the error correctly, I am changing the address buff points to inside with that malloc(), and then modify its contents, but the new malloc'd address inside is not returned. How could I do that without changing the parameters or the return value?
int itoa(int i, char *buff) {
int length = 0;
// get the length
long temp = 1;
while (temp <= i) {
length++;
temp *= 10;
}
buff = malloc(length + 1); // buff will have 'length' chars + one extra (\0)
int j = 0;
do { /* generate digits in reverse order */
buff[j++] = i % 10 + '0'; /* get next digit */
} while ((i /= 10) > 0); /* delete it */
buff[length] = '\0';
// reverse it
int k, l;
char c;
for (k = 0, l = length - 1; k<l; k++, l--) {
c = buff[k];
buff[k] = buff[l];
buff[l] = c;
}
printf("buff's now:%s\n", buff);
return 0;
}
int main() {
char *buff = NULL;
itoa(45, buff);
printf("%s\n", buff);
}
Your pointer isn't modified as it was copied. You can read more here. You can try this code after reading the above link.
#include <stdlib.h>
#include <stdio.h>
int itoa_(int i, char **parabuff)
{
int length = 0;
// get the length
long temp = 1;
while (temp <= i)
{
length++;
temp *= 10;
}
char *buff = malloc(length + 1); // buff will have 'length' chars + one extra (\0)
int j = 0;
do
{ /* generate digits in reverse order */
buff[j++] = i % 10 + '0'; /* get next digit */
} while ((i /= 10) > 0); /* delete it */
buff[length] = '\0';
// reverse it
int k, l;
char c;
for (k = 0, l = length - 1; k < l; k++, l--)
{
c = buff[k];
buff[k] = buff[l];
buff[l] = c;
}
printf("buff's now: %s\n", buff);
*parabuff = buff;
return 0;
}
int main()
{
char *buff = NULL;
itoa_(45, &buff);
printf("buff in main: %s\n", buff);
}
//OUTPUT
buff's now: 45
buff in main: 45

Convert long integer(decimal) to base 36 string (strtol inverted function in C)

I can use the strtol function for turning a base36 based value (saved as a string) into a long int:
long int val = strtol("ABCZX123", 0, 36);
Is there a standard function that allows the inversion of this? That is, to convert a long int val variable into a base36 string, to obtain "ABCZX123" again?
There's no standard function for this. You'll need to write your own one.
Usage example: https://godbolt.org/z/MhRcNA
const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *reverse(char *str)
{
char *end = str;
char *start = str;
if(!str || !*str) return str;
while(*(end + 1)) end++;
while(end > start)
{
int ch = *end;
*end-- = *start;
*start++ = ch;
}
return str;
}
char *tostring(char *buff, long long num, int base)
{
int sign = num < 0;
char *savedbuff = buff;
if(base < 2 || base >= sizeof(digits)) return NULL;
if(buff)
{
do
{
*buff++ = digits[abs(num % base)];
num /= base;
}while(num);
if(sign)
{
*buff++ = '-';
}
*buff = 0;
reverse(savedbuff);
}
return savedbuff;
}
One of the missing attributes of this "Convert long integer to base 36 string" is string management.
The below suffers from a potential buffer overflow when destination is too small.
char *long_to_string(char *destination, long num, int base);
(Assuming 32-bit long) Consider the overflow of below as the resultant string should be "-10000000000000000000000000000000", which needs 34 bytes to encode the string.
char buffer[33]; // Too small
long_to_string(buffer, LONG_MIN, 2); // Oops!
An alternative would pass in the buffer size and then provide some sort of error signaling when the buffer is too small.
char* longtostr(char *dest, size_t size, long a, int base)
Since C99, code instead could use a compound literal to provide the needed space - without calling code trying to compute the needed size nor explicitly allocate the buffer.
The returned string pointer from TO_BASE(long x, int base) is valid until the end of the block.
#include <assert.h>
#include <limits.h>
#define TO_BASE_N (sizeof(long)*CHAR_BIT + 2)
// v. compound literal .v
#define TO_BASE(x, b) my_to_base((char [TO_BASE_N]){""}, (x), (b))
char *my_to_base(char *buf, long a, int base) {
assert(base >= 2 && base <= 36);
long i = a < 0 ? a : -a; // use the negative side - this handle _MIN, _MAX nicely
char *s = &buf[TO_BASE_N - 1];
*s = '\0';
do {
s--;
*s = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[-(i % base)];
i /= base;
} while (i);
if (a < 0) {
s--;
*s = '-';
}
// Could add memmove here to move the used buffer to the beginning
return s;
}
#include <limits.h>
#include <stdio.h>
int main(void) {
long ip1 = 0x01020304;
long ip2 = 0x05060708;
long ip3 = LONG_MIN;
printf("%s %s\n", TO_BASE(ip1, 16), TO_BASE(ip2, 16), TO_BASE(ip3, 16));
printf("%s %s\n", TO_BASE(ip1, 2), TO_BASE(ip2, 2), TO_BASE(ip3, 2));
puts(TO_BASE(ip1, 8));
puts(TO_BASE(ip1, 36));
puts(TO_BASE(ip3, 10));
}
Here is another option with no need for source array of charaters, but less portable since not all character encodings have contiguous alphabetic characters, for example EBCDIC. Test HERE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <limits.h>
char get_chars(long long value)
{
if (value >= 0 && value <= 9)
return value + '0';
else
return value - 10 + 'A';
}
void reverse_string(char *str)
{
int len = strlen(str);
for (int i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
char* convert_to_base(char *res, int base, long long input)
{
bool flag = 0;
int index = 0;
if(input < 0){
input = llabs(input);
flag = 1;
}
else if(input == 0){
res[index++] = '0';
res[index] = '\0';
return res;
}
while(input > 0)
{
res[index++] = get_chars(input % base);
input /= base;
}
if(flag){
res[index++] = '-';
}
res[index] = '\0';
reverse_string(res);
return res;
}
int main() {
long long input = 0;
printf("** Integer to Base-36 **\n ");
printf("Enter a valid number: ");
scanf("%lld", &input);
if(input >= LLONG_MAX && input <= LLONG_MIN){
printf("Invalid number");
return 0;
}
int base = 36;
char res[100];
printf("%lld -> %s\n", input, convert_to_base(res, base, input));
return 0;
}

How can I split a long long integer into thousands for output?

For example if I have the number as 390000 it would need to be printed as 390 000.
If I have the number as 1200000 it would be printed as 1 200 000 etc.
Initially I thought about assigning the long long int to a string, and then writing if statements for each possible string length as there's only 11 possible lengths but this just seems really cumbersome and unnecessary.
Is there an easier way to do it?
If you're on a POSIX system and one of your locales uses the space as digit grouping symbol, use the apostrophe (') in printf() conversion specifier.
setlocale(LC_NUMERIC, "SOMETHING");
printf("%'d", 345678); // 345 678
See a previous answer of mine to the question "convert astronomically large numbers into human readable form in C/C++"
You can do it fairly easily by starting with a buffer sufficient in size to store the full long long number (and separators), and then using pointer arithmetic to insert a separator every 3rd number. For example, where MAXN is 32, you can do something like:
/** separate long long value every 3rd char into 's' */
char *sepnumber (char *s, long long val)
{
char numstr[MAXN] = "";
char *p = s + MAXN - 2;
size_t idx = 0, len = 0;
len = sprintf (numstr, "%lld", val);
while (len--) {
if (idx++ == 3) {
idx = 1;
*p-- = ' ';
}
*p = numstr[len];
if (len) p--;
}
for (idx = 0; *p; p++, idx++) s[idx] = *p; /* copy to s */
s[idx] = *p; /* nul-terminate */
return s;
}
A quick example would be:
#include <stdio.h>
#include <stdlib.h>
#define MAXN 32
char *sepnumber (char *s, long long val);
int main (int argc, char **argv) {
long long int lv = argc > 1 ? strtoll (argv[1], NULL, 10) : 1931583282;
char fmtnum[MAXN] = "";
printf (" %lld => %s\n", lv, sepnumber (fmtnum, lv));
return 0;
}
/** separate long long value every 3rd char into 's' */
char *sepnumber (char *s, long long val)
{
char numstr[MAXN] = "";
char *p = s + MAXN - 2;
size_t idx = 0, len = 0;
len = sprintf (numstr, "%lld", val);
while (len--) {
if (idx++ == 3) {
idx = 1;
*p-- = ' ';
}
*p = numstr[len];
if (len) p--;
}
for (idx = 0; *p; p++, idx++) s[idx] = *p; /* copy to s */
s[idx] = *p; /* nul-terminate */
return s;
}
Example Use/Output
$ ./bin/sepnum
1931583282 => 1 931 583 282
$ ./bin/sepnum 2212
2212 => 2 212
Here is a simple version without any nonsense. There are probably more efficient ways still, but if so, they do not include string handling or float numbers.
#include <stdio.h>
#include <inttypes.h>
#include <stdbool.h>
static void print_number (uint32_t n)
{
static bool remove_zeroes = true;
if(remove_zeroes)
{
remove_zeroes = false;
printf("%" PRIu32 " ", n);
}
else
{
printf("%.3" PRIu32 " ", n);
}
}
void print_number_with_spaces (uint32_t n)
{
bool remove_zeroes = true;
while(n > 1000)
{
uint32_t tmp = n;
uint32_t subtract = 1;
while(tmp > 1000)
{
tmp /= 1000;
subtract *= 1000;
}
print_number(tmp);
if(subtract >= 1000)
{
n -= tmp*subtract;
}
}
print_number(n);
}
int main(int argc, char* argv[])
{
print_number_with_spaces(1200000);
}
An easy way to print with spaces separating the thousands places uses recursion. Works for negative values too.
void print_1000(long long x) {
long long msgroups = x / 1000;
int lsgroup = x % 1000;
if (msgroups) {
print_1000(msgroups);
char separator = ' '; // adjust as deisred
printf("%c%03d", separator, abs(lsgroup));
} else {
printf("%d", lsgroup);
}
}
Sample usage
int main(void) {
print_1000(0); puts("");
print_1000(-1); puts("");
print_1000(LLONG_MAX); puts("");
print_1000(LLONG_MIN); puts("");
return 0;
}
Output
0
-1
9 223 372 036 854 775 807
-9 223 372 036 854 775 808
Another way using a Duff's Device:
#include <stdio.h>
static char *sep(char *str, long long value)
{
char tmp[32];
char *p = tmp;
char *q = str;
int len;
len = snprintf(tmp, sizeof tmp, "%lld", value);
if (*p == '-') { // Support for negatives
*q++ = *p++;
len--;
}
/*
* Consider 5 mod 3
* len % 3 is evaluated only once. E.g. 5 % 3 = 2
* jumps into the middle of the loop (in this case to "case 2:")
* case 2 and case 1 are evaluated
* loops until NUL is reached evaluating all cases
*/
switch (len % 3) do {
*q++ = ' ';
case 0: *q++ = *p++;
case 2: *q++ = *p++;
case 1: *q++ = *p++;
} while (*p);
*q = '\0';
return str;
}
int main(void)
{
char str[32];
printf("%s\n", sep(str, 1200000));
return 0;
}
Output
1 200 000
A quick solution I came up with is:
output = []
number = '1209873'
aux = reversed(list(number))
counter = 0
for digit in aux:
output.append(digit)
counter += 1
if counter % 3 == 0:
output.append(' ')
spaced_number = reduce(lambda x, y: x + y, reversed(output))
But I'm sure there are more efficient ways to solve your problem. ;)

How can I trim and pass an array of strings into a function?

How can I trim a string into pieces of N numbers of characters and then pass them as an array of strings into a function?
This in a part of my program that converts binary<->hex.
I tried doing the same thing with strings but it did not work.
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <String.h>
#define MAXDIGITS 8 // 8bits
int main()
{
int y;
printf("Binary-Hex convertor\n");
printf("Enter the Binary value : ");
scanf("%d", &y);
int i = MAXDIGITS - 1;
int array[MAXDIGITS];
while(y > 0)
{
array[i--] = y % 10;
y /= 10;
}
printf("%s", "-----------------\n");
printf("%s", "HEX:");
int x = array[0];
int x1 = array[1];
int x2 = array[2];
int x3 = array[3];
int x4 = array[4];
int x5 = array[5];
int x6 = array[6];
int x7 = array[7];
char buffer[50];
char buffer2[50];
char buffer3[50];
}
If its just binary to hex from a string then this is much easier....
char *input_string = "1001010101001010";
int count = 0;
int value = 0;
while ( *input_string != '\0' )
{
// Might be worth checking for only 0 and 1 in input string
value <<= 1;
value |= (int)((*input_string--) - '0');
if ( ++count == 8 || *input_string == '\0' )
{
// USE value to print etc, if you want to display use
// the following else you could store this in an array etc.
printf("%x ", value);
count = 0;
value = 0;
}
}
Do you have to null terminate the strings, do you have a limit on this memory used. Do you need to allocate the memory correctly etc? A bit more info would be useful
const char *input_string = "HELLO THIS IS SOME INPUT STRING";
int N = 4; // The number to split on
// Work out how many strings we will end up in
int number_of_strings = (strlen(input_string) + (N - 1)) / N;
// ALlow for an extra string if you want to null terminate the list
int memory_needed = ((number_of_strings + 1) * sizeof(char *)) + (number_of_strings * (N + 1));
char *buffer = malloc(memory_needed);
char **pointers = (char **)buffer;
char *string_start = (buffer + ((number_of_strings + 1) * sizeof(char *));
int count = 0;
while ( *input_string != '\0' )
{
// Fresh string
if ( count == 0 )
{
*pointers++ = string_start;
*pointers = NULL; // Lazy null terminate
}
// Copy a character
*string_start++ = *input_string++;
*string_start = '\0'; // Again lazy terminat
count++;
if ( count == N )
{
count = 0;
string_start++; // Move past the null terminated string
}
}
You can then pass (char **)buffer; to a routine. I havent actually tried this, ive been lazy in the terminating of the strings. You could just terminate at the end of a count run and the end of the while loop. This isnt exactly pretty code, but it should do the job. Bit more info on the other requirements might be good.

C str functions and malloc

I want to build a program which sum a big integers in C.
So I'm ready with the code. The program compiling pass successfully with mingw and Visual C++ compiler. But I have a problem with the run part. The strange thing is that when I debug the program in Visual Studio there is no problems but when I run it my Windows show that the program stop working.
This is the code :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include "sum.h"
int isNumber(char* number)
{
int lenght = strlen(number);
int i,result = 0;
for (i = 0 ; i < lenght ; i++)
{
if (isdigit(*number++))
{
result = 1;
}
else
{
result = 0;
break;
}
}
return result;
}
int cti(char ch)
{
return ch - '0';
}
char* addZeros(char* number,int lenght)
{
int num_lenght = strlen(number),size = abs(lenght - num_lenght),i;
char* zeros = (char*)malloc(size);
strcpy(zeros,"");
zeros[size - 1] = '\0';
for (i = 0 ; i < abs(lenght - num_lenght) ; i++)
{
strcpy(&zeros[i],"0");
}
strncat(zeros,number,size);
number = (char*)malloc(sizeof(char)*size);
strncpy(number,zeros,size);
return number;
}
char* sum(char* numberOne,char* numberTwo)
{
if (numberOne == NULL || numberTwo == NULL)
return NULL;
if (!isNumber(numberOne) || !isNumber(numberTwo))
return NULL;
int CF = 0;
int lenghtOne = strlen(numberOne),lenghtTwo = strlen(numberTwo);
if (lenghtOne == 0 || lenghtTwo == 0)
return lenghtOne == 0 ? numberTwo : numberOne;
int max = lenghtOne > lenghtTwo? lenghtOne : lenghtTwo,index;
char* result = (char*)malloc(max);
int res = 0;
result[max] = '\0';
if (lenghtOne > lenghtTwo) numberTwo=addZeros(numberTwo,strlen(numberOne));
else if (lenghtOne < lenghtTwo) numberOne = addZeros(numberOne,strlen(numberTwo));
for ( index = max - 1 ; index >=0 ; index--)
{
res = cti(numberOne[index]) + cti(numberTwo[index]);
if (((res%10) + CF) > 9)
{
int num = ((res%10) + CF);
result[index] = (char)((int)'0'+num%10);
CF = num / 10;
}
else
{
result[index] = (char)((int)'0'+((res%10) + CF));
CF = res / 10;
}
}
return result;
}
int main(int argc, char *argv[])
{
char* num = "12345678";
char* num2= "2341";
char* result = sum(num,num2);
printf("%s\n",result);
return 0;
}
I think that the problem is somewhere in the pointers but I'm not absolutely sure about this. Can anyone help me?
The amount of memory you are allocating is not sufficient. It does not include space for the null character terminating the string and it does not take into account changes in the length of the result for sums such as "9" + "1". You are then writing the null terminating character after the end of the array.
You should malloc with the length like this:
char* result = (char*)malloc(max + 2);
result[max] = '\0';
This is incorrect since you only allocated max characters for result. I've not studied the logic in detail but allocating max+1 characters would fix this particular problem.

Resources