Length of unsigned char *? [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
void HorspoolMatching(unsigned char T[], char P[])
{
int i = 0, k, m, n;
int count = 0;
//int *p;
int val;
ShiftTable(P);
m = strlen(P);
n = strlen(T);
i = m - 1;
while(i < n)
{
k = 0;
while((k < m ) && (P[m - 1 - k] == T[i - k]))
{
k++;
}
if(k == m)
{
count++;
i += m;
} else{
val = (int)T[i];
if (val < 0 || val >= MAX) {
i = i + m;
} else {
i = i + table[val];
}
}
}
printf("%d\n", count);
}
...
printf("Enter name of the data file: ");
scanf("%s", filenameFOUR);
FILE *fp4;
fp4 = fopen(filenameFOUR, "r");
if(fp4 == NULL)
{
printf("Error");
exit(0);
}
while((inc = fgetc(fp4)) != EOF)
{
buf[n++] = (char) inc;
}
fclose(fp4);
printf("Enter a pattern to search: ");
scanf("%s", pat2);
ftime(&before);
HorspoolMatching(buf, pat2);
ftime(&after);
int diffTime4 = (after.time - before.time)*1000 +
(after.millitm - before.millitm);
printf("Time it took: %d milliseconds.\n", diffTime4);
How do I get the length of the unsigned parameter without an error? I was advised to change to unsigned chars because my output is incorrect. Im trying to go through a test file to find matches using the horspool algorithm.
warning: passing 'unsigned char *' to parameter of type
'const char *' converts between pointers to integer types with different
sign [-Wpointer-sign]
n = strlen(T);
^
/usr/include/string.h:82:28: note: passing argument to parameter here
size_t strlen(const char *);

You could cast the unsigned char * to char * for strlen without ill effects. However, there is a far more pressing issue with your code.
Since the chars might be signed, P[m - 1 - k] == T[i - k] is incorrect: then P[m] would be signed and T[n] would be unsigned - the characters that have sign bit on wouldn't match (i.e. having unsigned value >= 128 on machine with CHAR_BIT 8). As the Horspool's algorithm uses the characters as index to arrays, it would be easiest to have both parameters as unsigned char[]. Even better: use a variable of type unsigned char * to represent them, while accepting char * as the argument:
void HorspoolMatching(char T[], char P[]) {
unsigned char *t = (unsigned char*)T;
unsigned char *p = (unsigned char*)P;
// and use t and p here on.
}
However, it is more common to write the matching so that it also accepts the length of the strings as parameters - often the length of the string is known beforehand so calculating it again within the function would be costly. Thus I'd recommend declaring the function as
char *HorspoolMatching(char T[], size_t T_len, char P[], size_t P_len);
void as the return value isn't useful either - I'd char * to the beginning of first match, or NULL if no match is found.

Related

How do I convert a really long string to binary in C?

I would like to convert a very long (arbitrary length, possibly 1000 characters long; university assignment) string into binary. How should I approach this problem? I have thought about it for a while, but I just can't seem to think of anything viable.
The string will be passed to me as const char *str. I want to read the number, which will be in Base 10, and convert it into binary.
Should I read certain number of least significant numbers and store them in unsigned long long int, and then work from there? Is there a better solution? I don't know how the method I suggested would pan out. I wanted to know if there's a better/easier way to do it.
Thank you.
Assuming your input is too large for the biggest integer type, you have to convert it to a unlimited size integer. For this purpose you can use gmplib. If you are not allowed to use external libraries, you can use a different approach:
is your string divisible by two (look at the last digit)?
if yes, write 0 to left side of your output
else, write 1 to left side of your output
divide the string by 2 (every digit)
repeat while string is not filled with 0
I am going to edit this answer, as soon as I wrote the code.
Here you go:
#include<stdbool.h>
#include<stdlib.h>
#include<memory.h>
#include<stdio.h>
typedef struct char_queue {
unsigned int len;
unsigned int capacity;
char* data;
} char_queue;
char_queue init_char_queue() {
return (char_queue) {
0,
4096,
malloc(4096)
};
}
void enqueue(char_queue* queue, char val) {
if (queue->len == queue->capacity) {
char* new_queue_data = malloc(queue->capacity + 4096);
memmove(new_queue_data, queue->data, queue->capacity);
free(queue->data);
queue->data = new_queue_data;
}
queue->len++;
queue->data[queue->capacity - queue->len] = val;
}
char* queue_get_arr(char_queue* queue) {
char* output = malloc(queue->len);
memcpy(output, &queue->data[queue->capacity - queue->len], queue->len);
return output;
}
void free_char_queue(char_queue* queue) {
if (queue->data) free(queue->data);
}
void convert_to_digit_arr(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
input[i] = input[i] - '0'; // '5' - '0' = 5
}
}
bool is_null(char* input, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
if (input[i] != 0) return false;
}
return true;
}
bool divisible_by_two(char* digit_arr, unsigned int len) {
return digit_arr[len - 1] % 2 == 0;
}
void divide_by_two(char* digit_arr, unsigned int len) {
for (unsigned int i = 0; i < len; i++) {
bool is_odd = digit_arr[i] % 2 == 1;
digit_arr[i] /= 2;
if (is_odd && i + 1 < len) { // and is not last (right) digit
digit_arr[i + 1] += 10;
}
}
}
int main(int argc, char** argv) {
for (int i = 1; i < argc; i++) {
unsigned int input_len = strlen(argv[i]);
char* input = malloc(input_len + 1);
strcpy(input, argv[i]);
convert_to_digit_arr(input, input_len);
char_queue queue = init_char_queue();
enqueue(&queue, 0); // null terminator to use the queue content as a string
while (!is_null(input, input_len)) {
enqueue(&queue, divisible_by_two(input, input_len) ? '0' : '1');
divide_by_two(input, input_len);
}
free(input);
char* output = queue_get_arr(&queue);
printf("%s\n", output);
free(output);
free_char_queue(&queue);
}
}
This is not the fastest approach, but it is very simple. Also feel free to optimize it.
How do I convert a really long string (as decimal characters) to binary?
Let us look at printing this.
print2(s)
If the decimal string is at least "2",
__ Divide the decimal string by 2 and notice its remainder.
__ Recursively call print2(s)
__ Print the remainder.
Else print the string.
Example code:
#include <stdio.h>
unsigned decimal_string_divide(char *dividend, unsigned divisor) {
// Remove a potential leading '0'
if (*dividend == '0') {
memmove(dividend, dividend+1, strlen(dividend));
}
// "divide", like we learned in grade school.
unsigned remainder = 0;
while (*dividend) {
unsigned sum = remainder*10 + (*dividend - '0');
remainder = sum%divisor;
*dividend = sum/divisor + '0';
dividend++;
}
return remainder;
}
void decimal_string_print_binary(char *dividend) {
//printf("<%s>\n", dividend); fflush(stdout);
if (dividend[0]) {
// If at least 2 digits or at least "2"
if (dividend[1] || (dividend[0] >= '2')) {
unsigned bit = decimal_string_divide(dividend, 2);
decimal_string_print_binary(dividend);
printf("%c", bit + '0');
} else {
printf("%c", *dividend);
}
}
}
void decimal_string_print_2(const char *dividend) {
printf("%-25s", dividend);
size_t sz = strlen(dividend) + 1;
char buf[sz]; // Use a VLA or allocate memory
strcpy(buf, dividend);
decimal_string_print_binary(buf);
printf("\n");
}
Test
int main(void) {
decimal_string_print_2("0");
decimal_string_print_2("1");
decimal_string_print_2("42");
decimal_string_print_2("8675309");
decimal_string_print_2("18446744073709551615");
}
Output
0 0
1 1
42 101010
8675309 100001000101111111101101
18446744073709551615 1111111111111111111111111111111111111111111111111111111111111111
To instead convert the string from decimal form into a binary string, allocate sufficient buffer (about log10(2) times string length) and instead of printing above, save to the buffer. Left for OP to do.
I am suggesting a better approach. whereby any arguments passed to a function that is not intended to be mutated, be received as a "const", and a local pointer be used to access the data of this "const".
IE:
void to_binary(const char *str) {
char *ptr = str;
...
Then use ptr.
I know that in this case, my argument is purely trivial and academic, but it is a good practice to get used to and may save you many headaches in the future.
Also, when dealing with binary data, use "unsigned char", to ensure that no type conversions are used. You will need bit 7 if the data is not ASCII or alike.

warning: assignment makes pointer from integer without a cast [-Wint-conversion] p = (i + 1) * 100; [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
I am trying to fill array with the numbers without using scanf. I encountered warning: assignment makes pointer from integer without a cast [-Wint-conversion]
p = (i + 1) * 100;
^
and when i try to print the array the array output random values. How do i solve it?
#include<stdio.h>
int main() {
int nums[8], i;
int *p;
p = nums;
for (int i = 0; i < 8; ++i)
{
p = (i + 1) * 100;
p++;
}
return 0;
}
You declared a pointer
int *p;
p = nums;
and then instead of assigning the element of the array pointed to by the pointer you are trying to assign the pointer itself with an integer value.
p = (i + 1) * 100;
It is evident that you mean
*p = (i + 1) * 100;
Pay attention to that it is a bad idea to use the magic number 8 in the for loop. It is better to use a named constant.
If you want to fill the array using a pointer in the for loop then the program can look the following way
#include<stdio.h>
int main( void )
{
enum { N = 8 };
int nums[N];
int init_value = 1;
for ( int *p = nums; p != nums + N; ++p )
{
*p = 100 * init_value++;
}
return 0;
}
Using this approach you can write a separate function that will initialize an array the following way
void init_array( int *a, size_t n, int value )
{
for ( int *p = a; p != a + n; ++p )
{
*p = 100 * value++;
}
}
In the assignment p = (i + 1) * 100, p is an int *, not an int, so the assignment would convert the integer (i + 1) * 100 to a pointer. Instead, use *p = (i + 1) * 100.

Error on hand-coded concatenate function (Segmentation fault (core dumped)) [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm trying to make a function that concatenates a, b, and c in a single variable called result.
#include <stdio.h>
const char* concat(char* a, char* b, char* c) {
char *result; // Concatenated variable (A + B)
int i; // Index of A, B and C
int ir; // Index of result
// result = A
for(i=0; a[i] != '\0'; i++) {
ir = i;
result[ir] = a[i];
} // → for
// result = A + B
ir++;
for(i = 0; b[i] != '\0'; i++) {
if (i == 0)
ir = ir + i;
result[ir] = b[i];
} // → for
// result = A + B + C
ir++;
for(i = 0; c[i] != '\0'; i++) {
ir = ir + i;
result[ir] = c[i];
} // → for
return result;
} // → concatenate()
But when I compile and run with the following block it results in Segmentation fault (core dumped) error. I've already searched about it (What is a segmentation fault?) but the insight didn't come. What am I doing wrong?
int main() {
char* a = "1234567";
char* b = "abcdefg";
char* c = "_______";
printf("%s", concat(a, b, c));
}
ERROR:
Segmentation fault (core dumped)
The code shown is trying to store data into an undefined buffer (result), and that's not not kosher. SOMEBODY has to allocate the space, either your function, or the caller by passing in a bounded output buffer.
Using the allocate-memory mechanism, you have to get the full size of all the strings in advance so you can allocate the full chunk at once. After allocating the full chunk, copy in the strings one at a time.
char *concat3(const char *a, const char *b, const char *c)
{
// get the required size in advance
size_t n = 0;
for (const char *ap = a; *ap; ap++) n++;
for (const char *bp = b; *bp; bp++) n++;
for (const char *cp = c; *cp; cp++) n++;
char *result = malloc(n + 1);
char *op = result;
while (*op = *a++) op++;
while (*op = *b++) op++;
while (*op = *c++) op++;
return result;
}
Also note that the parameters are const char * rather than char * to make sure everybody knows that concat3 - I changed the name - will not write to these input buffers.
However, the return value cannot be const because you have to free it, which I hope you remember to do.
EDIT I added a different version that writes into a bounded output buffer so there's no memory allocation required in the function because the caller is responsible for it:
char *concat(char *obuf, size_t osize, const char *a, const char *b, const char *c)
{
char *obuf_save = obuf;
const char *obuf_max = obuf + osize - 1;
while (obuf < obuf_max && (*obuf = *a++)) obuf++;
while (obuf < obuf_max && (*obuf = *b++)) obuf++;
while (obuf < obuf_max && (*obuf = *c++)) obuf++;
*obuf = 0;
return obuf_save;
}
The key part is passing the output buffer and size, and it promises not to overwrite the end of the buffer.
Key downside: you can't tell if it truncated or not. Depends on your application if this matters.
You're never initializing result, so it will have a random value, so you've got UB (undefined behavior), which can result in a segfault.
You have to do a malloc for result. And, it needs to have enough space to hold the length of all the concatenated strings.
Here's some updated code. Note that I did not thoroughly check your for loops, but, at first glance they seem to be okay.
But, you have to add an EOS at the end of result because the for loops do not do that.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
size_t
mystrlen(const char *buf)
{
const char *bp;
for (bp = buf; *bp != 0; ++bp);
return bp - buf;
}
#if 0
const char *
concat(char *a, char *b, char *c)
#else
char *
concat(const char *a, const char *b, const char *c)
#endif
{
char *result; // Concatenated variable (A + B)
int i; // Index of A, B and C
int ir; // Index of result
// NOTE/BUG: result is _never_ given a value
#if 1
size_t totlen = 0;
// we need to determine the total length of the result string
totlen += mystrlen(a);
totlen += mystrlen(b);
totlen += mystrlen(c);
result = malloc(totlen + 1);
*result = 0;
#endif
// result = A
for (i = 0; a[i] != '\0'; i++) {
ir = i;
result[ir] = a[i];
}
// result = A + B
ir++;
for (i = 0; b[i] != '\0'; i++) {
if (i == 0)
ir = ir + i;
result[ir] = b[i];
}
// result = A + B + C
ir++;
for (i = 0; c[i] != '\0'; i++) {
ir = ir + i;
result[ir] = c[i];
}
result[totlen] = 0;
return result;
}
Edit: This was my original post. But, as others have pointed out, it was not the real issue.
So, disregard this section altogether!
I'm leaving it in because several responders here also misread the intent of your function at first glance. So, you may wish to add more comments to clarify the use of arguments and return value.
When you do:
char* a = "1234567";
You are creating a pointer that points to a string literal. On most/many systems, the literal will be placed in read only memory.
So, you will segfault on a protection exception [because you're trying to write to read only memory].
Also, the target buffer needs to be large enough to contain the size of all the concatenated strings. As you have it, a is too short/small.
You could try:
char a[100] = "1234567";
This creates a writable buffer of length 100 that is initialized with the string. But, you'll still have extra space to accomodate the concatenated strings [up to a total length of 100].

how to convert a int variable to char *array in C with malloc?

I'm doing a school project and this problem came up.
by the way, i can't use library.
How to convert a int variable to char array?
I have tried this but it didn't work, tried a lot of other things and even magic doesn't work...
char *r = malloc(sizeof(char*));
int i = 1;
r[counter++] = (char) i;
Can someone help me?
Thank you for your time.
In your code, you should allocate for char size and not char *. Please try with this code segment
char *r = malloc(sizeof(char) * N); // Modified here
int i = 1;
r[counter++] = i & 0xff; // To store only the lower 8 bits.
You could also try this:
char *r = malloc(sizeof(char));
char *s = (char*)&i;
r[counter++] = s[0];
This is an other funny way to proceed and it allows you to access the full int with:
s[0], s[1], etc...
Do you mind losing precision? A char is generally 8 bits and an int is generally more. Any int value over 255 is going to be converted to its modulo 255 - unless you want to convert the int into as many chars as is takes to hold an int.
Your title seems ot say that, but none of the answers give so far do.
If so, you need to declare an array of char which is sizeof(int) / sizeof(char) and loop that many times, moving i >> 8 into r[looop_var]. There is no need at all to malloc, unless your teacher told you to do so. In whch case, don't forget to handle malloc failing.
Let's say something like (I am coding this w/o compiling it, so beware)
int numChars = sizeof(int) / sizeof(char);
char charArry[numChard]; // or malloc() later, if you must (& check result)
int convertMe = 0x12345678;
int loopVar;
for (loopVar = 0; loopvar < numChars)
{
charArry[loopVar ] = convertMe ;
convertMe = convertMe >> 8;
}
If you can't use the library, you can't use malloc.
But this will work:
int i = 0;
char *p = (char *)&i;
p[0] = 'H';
p[1] = 'i';
p[2] = '!';
p[3] = '\0';
printf("%s\n", p);
Assuming your int is 32bit or more (and your char is 8).
It then follows that if you have:
int i[100];
You can treat that as an array of char with a size equal to sizeof (i). i.e.
int i[100];
int sz = sizeof(i); // probably 400
char *p = (char *)i; // p[0] to p[sz - 1] is valid.
You can use a union instead. Assuming that sizeof int == 4,
typedef union {
int i;
char[4] cs;
} int_char;
int_char int_char_pun;
int_char_pun.i = 4;
for (int i = 0; i < 4; i++) {
putchar(int_char_pun.cs[i]);
}
Be careful; int_char.cs usually won't be a null-terminated string, or it might be, but with length < 4.
if you don't want to include the math library:
unsigned long pow10(int n);
void main(){
char test[6] = {0};
unsigned int testint = 2410;
char conversion_started = 0;
int i=0,j=0;float k=0;
for(i=sizeof(test);i>-1;i--){
k=testint/pow10(i);
if(k<1 && conversion_started==0) continue;
if(k >= 0 && k < 10){
test[j++]=k+0x30;
testint = testint - (k * pow10(i));
conversion_started=1;
}
}
test[j]=0x00;
printf("%s",test);
}
unsigned long pow10(int n){
long r = 1;
int q = 0;
if(n==0) return 1;
if(n>0){
for(q=0;q<n;q++) r = r * 10;
return r;
}
}
NOTE: I didn't care much about the char array length, so you might better choose it wisely.
hmm... what is wrong with the code below
char *r = malloc(sizeof(char) * ARR_SIZE);
int i = 1;
sprintf(r,"%d",i);
printf("int %d converted int %s",i,r);
will it now work for you

What is the proper way of implementing a good "itoa()" function?

I was wondering if my implementation of an "itoa" function is correct. Maybe you can help me getting it a bit more "correct", I'm pretty sure I'm missing something. (Maybe there is already a library doing the conversion the way I want it to do, but... couldn't find any)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
char * itoa(int i) {
char * res = malloc(8*sizeof(int));
sprintf(res, "%d", i);
return res;
}
int main(int argc, char *argv[]) {
...
// Yet, another good itoa implementation
// returns: the length of the number string
int itoa(int value, char *sp, int radix)
{
char tmp[16];// be careful with the length of the buffer
char *tp = tmp;
int i;
unsigned v;
int sign = (radix == 10 && value < 0);
if (sign)
v = -value;
else
v = (unsigned)value;
while (v || tp == tmp)
{
i = v % radix;
v /= radix;
if (i < 10)
*tp++ = i+'0';
else
*tp++ = i + 'a' - 10;
}
int len = tp - tmp;
if (sign)
{
*sp++ = '-';
len++;
}
while (tp > tmp)
*sp++ = *--tp;
return len;
}
// Usage Example:
char int_str[15]; // be careful with the length of the buffer
int n = 56789;
int len = itoa(n,int_str,10);
The only actual error is that you don't check the return value of malloc for null.
The name itoa is kind of already taken for a function that's non-standard, but not that uncommon. It doesn't allocate memory, rather it writes to a buffer provided by the caller:
char *itoa(int value, char * str, int base);
If you don't want to rely on your platform having that, I would still advise following the pattern. String-handling functions which return newly allocated memory in C are generally more trouble than they're worth in the long run, because most of the time you end up doing further manipulation, and so you have to free lots of intermediate results. For example, compare:
void delete_temp_files() {
char filename[20];
strcpy(filename, "tmp_");
char *endptr = filename + strlen(filename);
for (int i = 0; i < 10; ++i) {
itoa(endptr, i, 10); // itoa doesn't allocate memory
unlink(filename);
}
}
vs.
void delete_temp_files() {
char filename[20];
strcpy(filename, "tmp_");
char *endptr = filename + strlen(filename);
for (int i = 0; i < 10; ++i) {
char *number = itoa(i, 10); // itoa allocates memory
strcpy(endptr, number);
free(number);
unlink(filename);
}
}
If you had reason to be especially concerned about performance (for instance if you're implementing a stdlib-style library including itoa), or if you were implementing bases that sprintf doesn't support, then you might consider not calling sprintf. But if you want a base 10 string, then your first instinct was right. There's absolutely nothing "incorrect" about the %d format specifier.
Here's a possible implementation of itoa, for base 10 only:
char *itobase10(char *buf, int value) {
sprintf(buf, "%d", value);
return buf;
}
Here's one which incorporates the snprintf-style approach to buffer lengths:
int itobase10n(char *buf, size_t sz, int value) {
return snprintf(buf, sz, "%d", value);
}
A good int to string or itoa() has these properties;
Works for all [INT_MIN...INT_MAX], base [2...36] without buffer overflow.
Does not assume int size.
Does not require 2's complement.
Does not require unsigned to have a greater positive range than int. In other words, does not use unsigned.
Allows use of '-' for negative numbers, even when base != 10.
Tailor the error handling as needed. (needs C99 or later):
char* itostr(char *dest, size_t size, int a, int base) {
// Max text needs occur with itostr(dest, size, INT_MIN, 2)
char buffer[sizeof a * CHAR_BIT + 1 + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (base < 2 || base > 36) {
fprintf(stderr, "Invalid base");
return NULL;
}
// Start filling from the end
char* p = &buffer[sizeof buffer - 1];
*p = '\0';
// Work with negative `int`
int an = a < 0 ? a : -a;
do {
*(--p) = digits[-(an % base)];
an /= base;
} while (an);
if (a < 0) {
*(--p) = '-';
}
size_t size_used = &buffer[sizeof(buffer)] - p;
if (size_used > size) {
fprintf(stderr, "Scant buffer %zu > %zu", size_used , size);
return NULL;
}
return memcpy(dest, p, size_used);
}
I think you are allocating perhaps too much memory. malloc(8*sizeof(int)) will give you 32 bytes on most machines, which is probably excessive for a text representation of an int.
i found an interesting resource dealing with several different issues with the itoa implementation
you might wanna look it up too
itoa() implementations with performance tests
I'm not quite sure where you get 8*sizeof(int) as the maximum possible number of characters -- ceil(8 / (log(10) / log(2))) yields a multiplier of 3*. Additionally, under C99 and some older POSIX platforms you can create an accurately-allocating version with sprintf():
char *
itoa(int i)
{
int n = snprintf(NULL, 0, "%d", i) + 1;
char *s = malloc(n);
if (s != NULL)
snprintf(s, n, "%d", i);
return s;
}
HTH
You should use a function in the printf family for this purpose. If you'll be writing the result to stdout or a file, use printf/fprintf. Otherwise, use snprintf with a buffer big enough to hold 3*sizeof(type)+2 bytes or more.
sprintf is quite slow, if performance matters it is probably not the best solution.
if the base argument is a power of 2 the conversion can be done with a shift and masking, and one can avoid reversing the string by recording the digits from the highest positions. For instance, something like this for base=16
int num_iter = sizeof(int) / 4;
const char digits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
/* skip zeros in the highest positions */
int i = num_iter;
for (; i >= 0; i--)
{
int digit = (value >> (bits_per_digit*i)) & 15;
if ( digit > 0 ) break;
}
for (; i >= 0; i--)
{
int digit = (value >> (bits_per_digit*i)) & 15;
result[len++] = digits[digit];
}
For decimals there is a nice idea to use a static array big enough to record the numbers in the reversed order, see here
Integer-to-ASCII needs to convert data from a standard integer type
into an ASCII string.
All operations need to be performed using pointer arithmetic, not array indexing.
The number you wish to convert is passed in as a signed 32-bit integer.
You should be able to support bases 2 to 16 by specifying the integer value of the base you wish to convert to (base).
Copy the converted character string to the uint8_t* pointer passed in as a parameter (ptr).
The signed 32-bit number will have a maximum string size (Hint: Think base 2).
You must place a null terminator at the end of the converted c-string Function should return the length of the converted data (including a negative sign).
Example my_itoa(ptr, 1234, 10) should return an ASCII string length of 5 (including the null terminator).
This function needs to handle signed data.
You may not use any string functions or libraries.
.
uint8_t my_itoa(int32_t data, uint8_t *ptr, uint32_t base){
uint8_t cnt=0,sgnd=0;
uint8_t *tmp=calloc(32,sizeof(*tmp));
if(!tmp){exit(1);}
else{
for(int i=0;i<32;i++){
if(data<0){data=-data;sgnd=1;}
if(data!=0){
if(data%base<10){
*(tmp+i)=(data%base)+48;
data/=base;
}
else{
*(tmp+i)=(data%base)+55;
data/=base;
}
cnt++;
}
}
if(sgnd){*(tmp+cnt)=45;++cnt;}
}
my_reverse(tmp, cnt);
my_memcopy(tmp,ptr,cnt);
return ++cnt;
}
ASCII-to-Integer needs to convert data back from an ASCII represented string into an integer type.
All operations need to be performed using pointer arithmetic, not array indexing
The character string to convert is passed in as a uint8_t * pointer (ptr).
The number of digits in your character set is passed in as a uint8_t integer (digits).
You should be able to support bases 2 to 16.
The converted 32-bit signed integer should be returned.
This function needs to handle signed data.
You may not use any string functions or libraries.
.
int32_t my_atoi(uint8_t *ptr, uint8_t digits, uint32_t base){
int32_t sgnd=0, rslt=0;
for(int i=0; i<digits; i++){
if(*(ptr)=='-'){*ptr='0';sgnd=1;}
else if(*(ptr+i)>'9'){rslt+=(*(ptr+i)-'7');}
else{rslt+=(*(ptr+i)-'0');}
if(!*(ptr+i+1)){break;}
rslt*=base;
}
if(sgnd){rslt=-rslt;}
return rslt;
}
I don't know about good, but this is my implementation that I did while learning C
static int ft_getintlen(int value)
{
int l;
int neg;
l = 1;
neg = 1;
if (value < 0)
{
value *= -1;
neg = -1;
}
while (value > 9)
{
l++;
value /= 10;
}
if (neg == -1)
{
return (l + 1);
}
return (l);
}
static int ft_isneg(int n)
{
if (n < 0)
return (-1);
return (1);
}
static char *ft_strcpy(char *dest, const char *src)
{
unsigned int i;
i = 0;
while (src[i] != '\0')
{
dest[i] = src[i];
i++;
}
dest[i] = src[i];
return (dest);
}
char *ft_itoa(int n)
{
size_t len;
char *instr;
int neg;
neg = ft_isneg(n);
len = ft_getintlen(n);
instr = (char *)malloc((sizeof(char) * len) + 1);
if (n == -2147483648)
return (ft_strcpy(instr, "-2147483648"));
if (!instr)
return (NULL);
if (neg == -1)
n *= -1;
instr[len--] = 0;
if (n == 0)
instr[len--] = 48;
while (n)
{
instr[len--] = ((n % 10) + 48);
n /= 10;
}
if (neg == -1)
instr[len] = '-';
return (instr);
}
This should work:
#include <string.h>
#include <stdlib.h>
#include <math.h>
char * itoa_alloc(int x) {
int s = x<=0 ? 1 ? 0; // either space for a - or for a 0
size_t len = (size_t) ceil( log10( abs(x) ) );
char * str = malloc(len+s + 1);
sprintf(str, "%i", x);
return str;
}
If you don't want to have to use the math/floating point functions (and have to link in the math libraries) you should be able to find non-floating point versions of log10 by searching the Web and do:
size_t len = my_log10( abs(x) ) + 1;
That might give you 1 more byte than you needed, but you'd have enough.
There a couple of suggestions I might make. You can use a static buffer and strdup to avoid repeatedly allocating too much memory on subsequent calls. I would also add some error checking.
char *itoa(int i)
{
static char buffer[12];
if (snprintf(buffer, sizeof(buffer), "%d", i) < 0)
return NULL;
return strdup(buffer);
}
If this will be called in a multithreaded environment, remove "static" from the buffer declaration.
This is chux's code without safety checks and the ifs. Try it online:
char* itostr(char * const dest, size_t const sz, int a, int const base) {
bool posa = a >= 0;
char buffer[sizeof a * CHAR_BIT + 1];
static const char digits[36] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char* p = &buffer[sizeof buffer - 1];
do {
*(p--) = digits[abs(a % base)];
a /= base;
} while (a);
*p = '-';
p += posa;
size_t s = &buffer[sizeof(buffer)] - p;
memcpy(dest, p, s);
dest[s] = '\0';
return dest;
}
main()
{
int i=1234;
char stmp[10];
#if _MSC_VER
puts(_itoa(i,stmp,10));
#else
puts((sprintf(stmp,"%d",i),stmp));
#endif
return 0;
}

Resources