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.
Related
I'm trying to convert an integer to a binary String (see code below). I've already looked at several similar code snippets, and can't seem to find the reason as to why this does not work. It not only doesn't produce the correct output, but no output at all. Can somebody please explain to me in detail what I'm doing wrong?
#include <stdio.h>
#include <stdlib.h>
char* toBinaryString(int n) {
char *string = malloc(sizeof(int) * 8 + 1);
if (!string) {
return NULL;
}
for (int i = 31; i >= 0; i--) {
string[i] = n & 1;
n >> 1;
}
return string;
}
int main() {
char* string = toBinaryString(4);
printf("%s", string);
free(string);
return 0;
}
The line
string[i] = n & 1;
is assigning integers 0 or 1 to string[i]. They are typically different from the characters '0' and '1'. You should add '0' to convert the integers to characters.
Also, as #EugeneSh. pointed out, the line
n >> 1;
has no effect. It should be
n >>= 1;
to update the n's value.
Also, as #JohnnyMopp pointed out, you should terminate the string by adding a null-character.
One more point it that you should check if malloc() succeeded. (It is done in the function toBinaryString, but there is no check in main() before printing its result)
Finally, It doesn't looks so good to use a magic number 31 for the initialization of for loop while using sizeof(int) for the size for malloc().
Fixed code:
#include <stdio.h>
#include <stdlib.h>
char* toBinaryString(int n) {
int num_bits = sizeof(int) * 8;
char *string = malloc(num_bits + 1);
if (!string) {
return NULL;
}
for (int i = num_bits - 1; i >= 0; i--) {
string[i] = (n & 1) + '0';
n >>= 1;
}
string[num_bits] = '\0';
return string;
}
int main() {
char* string = toBinaryString(4);
if (string) {
printf("%s", string);
free(string);
} else {
fputs("toBinaryString() failed\n", stderr);
}
return 0;
}
The values you are putting into the string are either a binary zero or a binary one, when what you want is the digit 0 or the digit one. Try string[i] = (n & 1) + '0';. Binary 0 and 1 are non-printing characters, so that's why you get no output.
#define INT_WIDTH 32
#define TEST 1
char *IntToBin(unsigned x, char *buffer) {
char *ptr = buffer + INT_WIDTH;
do {
*(--ptr) = '0' + (x & 1);
x >>= 1;
} while(x);
return ptr;
}
#if TEST
#include <stdio.h>
int main() {
int n;
char str[INT_WIDTH+1]; str[INT_WIDTH]='\0';
while(scanf("%d", &n) == 1)
puts(IntToBin(n, str));
return 0;
}
#endif
im trying to to multipication in two string;
after i'm done the code shows me the answer with all the '0' from the calloc.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef char* verylong;
verylong input_long(void) {
int len = sizeof(char),size=0,c,i=0;
verylong num = malloc(len);
char ch;
size = len;
if (num != NULL) {
while ((c = getchar()) != '\n' && c != EOF) {
ch = (char)c;
if (isdigit(ch))
num[i++] = ch;
else
return NULL;
if (i == size) {
size = i + len;
if ((num = realloc(num, size)) == NULL)
return NULL;
}
}
}
else
return NULL;
num[i] = '\0';
return num;
}
verylong_multiply(verylong num1, verylong num2) {
int long1 = strlen(num1), long2 = strlen(num2);
verylong ret = calloc(long1 + long2 +1, sizeof(char));
_strrev(num1);
_strrev(num2);
int carry = 0;
for (int i = 0; i < long2; i++) {
int dig2 = num2[i]-'0';
carry = 0;
for (int j = 0; j < long1; j++) {
int dig1 = num1[j]-'0';
int temp = ret[i+j]-'0';
int cur = dig1 * dig2 + temp + carry;
ret[i+j] = cur % 10+'0';
carry = cur / 10;
}
if (carry>0)
ret[i+long1] = carry +'0';
}
_strrev(ret);
return ret;
}
void main() {
char* a = input_long();
char* b = input_long();
printf(multiply(a, b));
}
this is the whole code, the output seems to keep give me the answer of the two string (10*10) 580, it keeps adding the multiply if '0' (48 in ascii).
There are several problems other than the general design of the algorithm and the data structure (a struct which stores the size alongside with an array of digits, starting from the least significant one, would ease all the calculations).
verylong_multiply(verylong num1, verylong num2) {
if (strlen(num1) == 0 || strlen(num2) == 0) return '0';
Here there is at least a copy-paste error, either the function is verylong multiply(...) or the return type is missing. Also, if we assume (and we shouldn't) that verylong is a typedef of char *, that return '0'; is plain wrong. '0' is a char, not a char *.
There seems to be a confusion, throughout the whole snippet, between '0', '\0' and NULL.
This line
verylong ret = calloc(sizeof(char) , long1 + long2 + 1);
// ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ Those should be switched
Will allocate the array and fill it with zeroes, not '0'.
If you want to fill it with '0' (except for the null-terminator), you could use
memset(ret, '0', long1 + long2);
So that, later in the code, you could also change this line
int temp = ret[i+j]; // --> int temp = ret[i+j] - '0';
int cur = dig1 * dig2 + temp + carry;
ret[i+j] = cur % 10 + '0';
Thrn, before reversing the string and return it, you could transform the eventual last '0' into '\0', to avoid having, say, 10 * 123 = 01230 instead of 1230.
Note that the chosen data structure forces you to reverse the strings representing the numbers and to calculate their lengths every time you call this function and you should also reverse them back to their original state, if you plan to use them again.
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);
More specifically, how do I change'
char tempList[256] = "1 -2 -8 4 5";
into something like this:
int tempListNum[256] = {1, -2, -8, 4, 5};
?
I tried this, but I don't know how to append the array.
for (int j = 0; j < 256; j++)
{
if(TEMPS[j] == 45 && (TEMPS[j+1] >= 48 && TEMPS[j+2] >= 48))
{
numToAppend = ((TEMPS[j+1]-'0')*10 + (TEMPS[j+2]-'0')) * -1;
}
if(TEMPS[j] == 45 && TEMPS[j+1] >= 48)
{
numToAppend = (TEMPS[j+1]-'0') * -1;
}
if(TEMPS[j] >= 48)
{
numToAppend = TEMPS[j]-'0';
}
if(TEMPS[j] >= 48 && TEMPS[j+1] >= 48)
{
numToAppend = TEMPS[j]*10 + TEMPS[j+1];
}
}
you can use strtok with space as separator and then use atoi standard library function
Write a function that goes through tempList char by char:
While it encounters only numbers, it should turn them into an int. If there are more than 1 digit, it should multiply the first digit with 10 and add then add it to the int, etc.
When it encounters a space, it should add the newly created int to tempListNum and skip the space.
When it encounters a minus sign, it should multiply the currently created int with -1.
Repeat these steps until end of list.
You can try this
unsigned char index1 = 0,index2 =0;
int PrevValue = 0;
for(;index1 <= 255;index1 ++)
{
if(tempList[index1] != ' ') //space
{
tempListNum[index2] = PrevValue*10 + (tempList[index1]-0x30);
PrevValue = tempListNum[index2] ;
}
else
{
PrevValue = 0;
index2++;
}
}
You can add further optimizations and other validations.
This isn't terribly difficult. I'd recommend a custom strtoi function instead of atoi since atoi allows for little error handling. For example, atoi("1.3") would return 1 with no other way to get other information like the fact that ".3" makes it not an integer. Moreover, the value 1 is obviously within the range of the int type, so even errno may not be of help.
That is why I write and use strtoi below, which uses the C library's strtol function and has the same behaviors. If you need help understanding what strtoi does, look up documentation for strtol since they're pretty much the same except for the range of valid values (between INT_MIN and INT_MAX, both inclusive, instead of between LONG_MIN and LONG_MAX, both inclusive).
#include <stdio.h>
#include <stdlib.h> //strtol
#include <string.h> //strtok
#include <limits.h> //INT_MIN, INT_MAX
#include <errno.h> //errno, ERANGE
int
strtoi (const char *s, char **rem, int base)
{
long n;
int esave = errno;
errno = 0;
n = strtol (s, rem, base);
if (n < INT_MIN || n > INT_MAX)
errno = ERANGE;
if (errno)
{
if (n == LONG_MAX)
return INT_MAX;
return INT_MIN;
}
errno = esave;
return (int) n;
}
int
main (void)
{
char tempList[256] = "1 -2 -8 4 5";
int tempListNum[128] = {0};
int i, n;
char *listPtr;
char *listPtr2;
listPtr = strtok (tempList, " ");
for (i = 0;
listPtr != NULL && (size_t) i < sizeof tempListNum / sizeof tempListNum[0];
++i)
{
errno = 0;
n = strtoi (listPtr, &listPtr2, 10);
if (*listPtr2)
{
fprintf (stderr, "error: value `%s' is not an integer ... ignoring value\n", listPtr);
--i;
}
// value out of range or some other implementation-defined error
else if (errno)
{
perror (listPtr);
}
listPtr = strtok (NULL, " ");
}
// n is now the number of items in the array
n = i;
for (i = 0; i < n; ++i)
printf ("%d\n", tempListNum[i]);
}
You could obviously avoid strtok and just use strtoi by itself. That might actually be a cleaner solution!
Is this a homework assignment, or maybe a interview question?
I haven't tested this, but you could do something like this:
#define enum _error {
success = 0,
parse_error,
out_of_memory,
invalid_arg,
insuficient_buffer
} error;
error parse_int(
char **pp,
int *val)
{
error e = success;
char neg = 0;
if (!pp || !*pp || !val) {
e = invalid_arg;
goto exit;
}
*val = 0;
while (**pp) {
if (**pp == '-') {
if (val) {
e = parse_error;
goto exit;
}
neg = 1;
}
else if (**pp >= '0' **pp <= '9') {
*val *= 10;
*val += **pp - '0';
}
else {
break;
}
++*pp;
}
if (neg) {
*val *= -1;
}
exit:
return e;
}
error parse_array_of_ints(
char *p,
unsigned int parsed_ints_size,
int **parsed_ints)
{
error e = success;
unsigned int cur = 0;
if (!p || !parsed_ints) {
e = invalid_arg;
goto exit;
}
for (;;) {
while (*p && *p != '-' && *p < '0' && *p > '9') {
p++;
}
if (!*p) {
break;
}
if (cur = parsed_ints_size) {
e = insuficient_buffer;
goto exit;
}
e = parse_int(&p, parsed_ints+cur);
if (e != success) {
goto exit;
}
cur++;
}
exit:
return e;
}
For example, with while loop and functions sscanf and strtok from strings.h.
#include <stdio.h>
#include <string.h>
int main (void)
{
char tempList[256] = "1 -2 -8 4 5";
int tempListNum[256] = {0};
int cnt = 0;
int tmp = 0;
char * str = strtok (tempList," ");
while(str != NULL)
{
if(sscanf(str, "%d", &tmp))
{
tempListNum[cnt] = tmp;
cnt++;
}
// read next number
str = strtok (NULL," ");
}
// test output
for(tmp = 0; tmp < cnt; tmp++)
{
printf("%d ", tempListNum[tmp]);
}
return 0;
}
Tested in Visual Studio 2012.
Consider this short example:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char tempList[256] = "1 -2 -8 4 5";
int tempListNum[256] = {0};
int numCnt = 0;
char * pEnd = tempList;
int number = 0;
while( strlen(pEnd) > 0)
{
tempListNum[numCnt] = strtol (pEnd,&pEnd,0);
numCnt++;
}
for(number = 0; number < numCnt; number++)
{
printf("%d ", tempListNum[number]);
}
return 0;
}
You can try this :
char tempList[256] = "1 -2 -8 4 5";
int tempListNum[256]
int i=0,k=0;
while(i<256)
{
int num=0;
for(int j=0;tempList[j]!=' ';j++)
{
int neg=0,counter=0; //Not worked in C for a long time and I am not sure if it supports Bools
if(a[j]=='-')
neg=1;
else
num=num*10+int(tempList[j])-int('0');
counter++;
}
if(neg==1)
num=-num;
tempListNum[k]=num;
k++; i+=counter;
}
use this: it works on me.
#include <stdio.h>
#include <ctype.h>
#include <math.h>
int main() {
char tempList[256] = "1 -2 -82 43 5";
char tempNumber[10];
int tempNumberCounter = 0;
int i, j,counter=0, isNegative = 1;
int numTempList[256] = {0};
for(i=0; tempList[i] != '\0'; i++) {
if(tempList[i-1] == '-') {
isNegative = -1;
}
if(isdigit(tempList[i])) {
tempNumber[tempNumberCounter] = tempList[i];
tempNumberCounter++;
}
if(tempList[i] == ' ' || tempList[i+1] == '\0') {
tempNumber[tempNumberCounter] = '\0';
for(j=0; j<strlen(tempNumber); j++) {
numTempList[counter] += (tempNumber[j] - '0') * pow(10, strlen(tempNumber)-j-1);
}
numTempList[counter] *= isNegative;
counter++;
tempNumberCounter = 0;
*tempNumber = 0;
isNegative = 1;
}
}
for(i=0; numTempList[i] != 0; i++) {
printf("%d ", numTempList[i]);
}
return 0;
}
numTempList is the converted array from tempList. this is just a sample implementation of char to int array, you can refactor this into functions so that you can reuse this functionality..
Modified:
Now it can also read multiple digits
I have some program which decompress some string which is already mentioned here: How to decompres array of char in c. After I finished it I have problem with function free (without it, it works ok). There is some strange behaviour and the last assert fails because of : Aborted; core dumped;
when I debug this program I found that problem is in this cycle:
for (j = 0; j < max - 1; j++) {
vysledek[index] = src[i - pom];
printf("cccc%d\n%s\n", j,vysledek);
printf("xxx%c", src[i - pom]);
index++;
}
it prints:
...
xxx#cccc19
HHeeeeeellllllllooooooooooooooo#####################�
xxx#cccc20
HHeeeeeellllllllooooooooooooooo######################
xxx#cccc21
HHeeeeeellllllllooooooooooooooo#######################
xxx#cccc22
HHeeeeeellllllllooooooooooooooo########################
xxx#cccc23
HHeeeeeellllllllooooooooooooooo#########################Hello______________________________world!
xxx#cccc24
HHeeeeeellllllllooooooooooooooo##########################ello______________________________world!
...
can someone explain me this ? How can Hello world from second assert discover in third one ?
whole program is here:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
char * decompress(const char * src) {
int max = 0;
int pom = 1;
int maxSize = 0;
int index = 0;
int isNumber = 0;
int i;
for (i = 0; src[i] != 0; i++) {
max = 0;
isNumber = 0;
while (isdigit(src[i])) {
int digit = (src[i] - '0');
max = max * 10 + digit;
i++;
isNumber = 1;
}
if (max == 0 && !isNumber) {
max = 1;
}
maxSize = maxSize + max;
}
char *vysledek = (char*) malloc((maxSize) * sizeof (int));
for (i = 0; src[i] != 0; i++) {
max = 0;
pom = 0;
isNumber = 0;
while (isdigit(src[i])) {
int digit = (src[i] - '0');
max = max * 10 + digit;
i++;
pom++;
isNumber = 1;
}
if (!isNumber) {
vysledek[index] = src[i];
//printf("%c", src[i]);
index++;
} else {
i--;
int j;
if (max < 1) {
index--;
}
for (j = 0; j < max - 1; j++) {
vysledek[index] = src[i - pom];
//printf("cccc%d\n%s\n", j,vysledek);
//printf("xxx%c", src[i - pom]);
index++;
}
}
//printf("\n%d\n", index);
}
return vysledek;
}
int main(int argc, char * argv []) {
char * res;
assert(!strcmp(
(res = decompress("Hello world!")),
"Hello world!"));
//free(res);
assert(!strcmp(
(res = decompress("Hello_30world!")),
"Hello______________________________world!"));
//free(res);
assert(!strcmp(
(res = decompress("H2e6l8o15 35w5o6r-2d0!!")),
"HHeeeeeellllllllooooooooooooooo wwwwwoooooor--!!"));
//free(res);
return 0;
}
The problem is, that you compare a null-terminated string with a not-null-terminated string.
In your function decompress() you need to reserve one more int and add the missing \0 to the copied buffer.
char *vysledek = (char*) malloc((maxSize) * sizeof (int) + sizeof(int));
[...]
vysledek[index] = '\0';