My task is to convert a float or integer value to string in C. I can't use sprintf since I am working in embedded platform. So I thought to use something like this.
#define CURRENT(STRING,S_NO,VALUE) (str = "S"#S_NO#VALUE"A")
and invoking it like this
int a=10,b=20;
CURRENT(str,a,b);
So str should be S1020A. But I am getting SabA.
What am I doing wrong here?
Macros are evaluated before compilation so CURRENT(str,a,b); is expanded using the variable names a and b rather than their values which may only be available at runtime.
To convert an int to a char array at runtime without use of sprintf etc. use itoa if available or you could write a function like the following (untested!)
#define MAX_INT_STRING_BYTES (11)
void IntToString(int val, char* str)
{
char reversed[MAX_INT_STRING_BYTES]
int index, i = 0;
bool negative = false;
if (val == 0) {
*str++ = '0';
*str = '\0';
return;
}
if (val < 0) {
negative = true;
}
while(val != 0) {
reversed[index++] = (char)('0' + abs(val % 10));
val /= 10;
}
if (negative) {
*str++ = '-';
}
for (i = index; i > 0; i--) {
*str++ = reversed[i - 1]);
}
*str = '\0';
}
It only knows what the value of a and b is at runtime, and preprocessor directives are resolved at compile time. Thus what you're trying to do won't work.
You can however do something like:
#define CURRENT(STRING,S_NO,VALUE) sprintf(STRING, "S%i%iA", S_NO, VALUE)
Or just make it a function.
Or just call the sprintf directly instead of CURRENT.
Related
It is possible to convert integer to string in C without sprintf?
There's a nonstandard function:
char *string = itoa(numberToConvert, 10); // assuming you want a base-10 representation
Edit: it seems you want some algorithm to do this. Here's how in base-10:
#include <stdio.h>
#define STRINGIFY(x) #x
#define INTMIN_STR STRINGIFY(INT_MIN)
int main() {
int anInteger = -13765; // or whatever
if (anInteger == INT_MIN) { // handle corner case
puts(INTMIN_STR);
return 0;
}
int flag = 0;
char str[128] = { 0 }; // large enough for an int even on 64-bit
int i = 126;
if (anInteger < 0) {
flag = 1;
anInteger = -anInteger;
}
while (anInteger != 0) {
str[i--] = (anInteger % 10) + '0';
anInteger /= 10;
}
if (flag) str[i--] = '-';
printf("The number was: %s\n", str + i + 1);
return 0;
}
Here's an example of how it might work. Given a buffer and a size, we'll keep dividing by 10 and fill the buffer with digits. We'll return -1 if there is not enough space in the buffer.
int
integer_to_string(char *buf, size_t bufsize, int n)
{
char *start;
// Handle negative numbers.
//
if (n < 0)
{
if (!bufsize)
return -1;
*buf++ = '-';
bufsize--;
}
// Remember the start of the string... This will come into play
// at the end.
//
start = buf;
do
{
// Handle the current digit.
//
int digit;
if (!bufsize)
return -1;
digit = n % 10;
if (digit < 0)
digit *= -1;
*buf++ = digit + '0';
bufsize--;
n /= 10;
} while (n);
// Terminate the string.
//
if (!bufsize)
return -1;
*buf = 0;
// We wrote the string backwards, i.e. with least significant digits first.
// Now reverse the string.
//
--buf;
while (start < buf)
{
char a = *start;
*start = *buf;
*buf = a;
++start;
--buf;
}
return 0;
}
Unfortunately none of the answers above can really work out in a clean way in a situation where you need to concoct a string of alphanumeric characters.There are really weird cases I've seen, especially in interviews and at work.
The only bad part of the code is that you need to know the bounds of the integer so you can allocate "string" properly.
In spite of C being hailed predictable, it can have weird behaviour in a large system if you get lost in the coding.
The solution below returns a string of the integer representation with a null terminating character. This does not rely on any outer functions and works on negative integers as well!!
#include <stdio.h>
#include <stdlib.h>
void IntegertoString(char * string, int number) {
if(number == 0) { string[0] = '0'; return; };
int divide = 0;
int modResult;
int length = 0;
int isNegative = 0;
int copyOfNumber;
int offset = 0;
copyOfNumber = number;
if( number < 0 ) {
isNegative = 1;
number = 0 - number;
length++;
}
while(copyOfNumber != 0)
{
length++;
copyOfNumber /= 10;
}
for(divide = 0; divide < length; divide++) {
modResult = number % 10;
number = number / 10;
string[length - (divide + 1)] = modResult + '0';
}
if(isNegative) {
string[0] = '-';
}
string[length] = '\0';
}
int main(void) {
char string[10];
int number = -131230;
IntegertoString(string, number);
printf("%s\n", string);
return 0;
}
You can use itoa where available. If it is not available on your platform, the following implementation may be of interest:
https://web.archive.org/web/20130722203238/https://www.student.cs.uwaterloo.ca/~cs350/common/os161-src-html/atoi_8c-source.html
Usage:
char *numberAsString = itoa(integerValue);
UPDATE
Based on the R..'s comments, it may be worth modifying an existing itoa implementation to accept a result buffer from the caller, rather than having itoa allocate and return a buffer.
Such an implementation should accept both a buffer and the length of the buffer, taking care not to write past the end of the caller-provided buffer.
int i = 24344; /*integer*/
char *str = itoa(i);
/*allocates required memory and
then converts integer to string and the address of first byte of memory is returned to str pointer.*/
Let‘s assume we have a char array and a sequence. Next we would like to check if the char array contains the special sequence WITHOUT <string.h> LIBRARY: if yes -> return true; if no -> return false.
bool contains(char *Array, char *Sequence) {
// CONTAINS - Function
for (int i = 0; i < sizeof(Array); i++) {
for (int s = 0; s < sizeof(Sequence); s++) {
if (Array[i] == Sequence[i]) {
// How to check if Sequence is contained ?
}
}
}
return false;
}
// in Main Function
char *Arr = "ABCDEFG";
char *Seq = "AB";
bool contained = contains(Arr, Seq);
if (contained) {
printf("Contained\n");
} else {
printf("Not Contained\n");
}
Any ideas, suggestions, websites ... ?
Thanks in advance,
Regards, from ∆
The simplest way is the naive search function:
for (i = 0; i < lenS1; i++) {
for (j = 0; j < lenS2; j++) {
if (arr[i] != seq[j]) {
break; // seq is not present in arr at position i!
}
}
if (j == lenS2) {
return true;
}
}
Note that you cannot use sizeof because the value you seek is not known at run time. Sizeof will return the pointer size, so almost certainly always four or eight whatever the strings you use. You need to explicitly calculate the string lengths, which in C is done by knowing that the last character of the string is a zero:
lenS1 = 0;
while (string1[lenS1]) lenS1++;
lenS2 = 0;
while (string2[lenS2]) lenS2++;
An obvious and easy improvement is to limit i between 0 and lenS1 - lenS2, and if lenS1 < lenS2, immediately return false. Obviously if you haven't found "HELLO" in "WELCOME" by the time you've gotten to the 'L', there's no chance of five-character HELLO being ever contained in the four-character remainder COME:
if (lenS1 < lenS2) {
return false; // You will never find "PEACE" in "WAR".
}
lenS1minuslenS2 = lenS1 - lenS2;
for (i = 0; i < lenS1minuslenS2; i++)
Further improvements depend on your use case.
Looking for the same sequence among lots of arrays, looking for different sequences always in the same array, looking for lots of different sequences in lots of different arrays - all call for different optimizations.
The length and distribution of characters within both array and sequence also matter a lot, because if you know that there only are (say) three E's in a long string and you know where they are, and you need to search for HELLO, there's only three places where HELLO might fit. So you needn't scan the whole "WE WISH YOU A MERRY CHRISTMAS, WE WISH YOU A MERRY CHRISTMAS AND A HAPPY NEW YEAR" string. Actually you may notice there are no L's in the array and immediately return false.
A balanced option for an average use case (it does have pathological cases) might be supplied by the Boyer-Moore string matching algorithm (C source and explanation supplied at the link). This has a setup cost, so if you need to look for different short strings within very large texts, it is not a good choice (there is a parallel-search version which is good for some of those cases).
This is not the most efficient algorithm but I do not want to change your code too much.
size_t mystrlen(const char *str)
{
const char *end = str;
while(*end++);
return end - str - 1;
}
bool contains(char *Array, char *Sequence) {
// CONTAINS - Function
bool result = false;
size_t s, i;
size_t arrayLen = mystrlen(Array);
size_t sequenceLen = mystrlen(Sequence);
if(sequenceLen <= arrayLen)
{
for (i = 0; i < arrayLen; i++) {
for (s = 0; s < sequenceLen; s++)
{
if (Array[i + s] != Sequence[s])
{
break;
}
}
if(s == sequenceLen)
{
result = true;
break;
}
}
}
return result;
}
int main()
{
char *Arr = "ABCDEFG";
char *Seq = "AB";
bool contained = contains(Arr, Seq);
if (contained)
{
printf("Contained\n");
}
else
{
printf("Not Contained\n");
}
}
Basically this is strstr
const char* strstrn(const char* orig, const char* pat, int n)
{
const char* it = orig;
do
{
const char* tmp = it;
const char* tmp2 = pat;
if (*tmp == *tmp2) {
while (*tmp == *tmp2 && *tmp != '\0') {
tmp++;
tmp2++;
}
if (n-- == 0)
return it;
}
tmp = it;
tmp2 = pat;
} while (*it++ != '\0');
return NULL;
}
The above returns n matches of substring in a string.
I'm trying to do a simple function to convert a number codified in a string form to a float, using the function below (attached also), without using the function strtof.
I'm getting wrong values, could somebody solve this? Why is this giving me incorrect values?
For example if the input string is "123456789.123" the function will return a float value of 123456789.123...
Im using DevC++
if string == "12345678"
output = 12345678.000000 (CORRECT)
if string == "-12345678"
output = -12345678.000000 (CORRECT)
if string == "123456789"
output = 123456792.000000 (INCORRECT)
if string == "-123456789"
output = -123456792.000000 (INCORRECT)
if string == "1000.1"
output = 999.799988 (INCORRECT)
if string == "-1000.1"
-output = -999.799988 (INCORRECT)
My code so far is:
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
float StringToFloat (uint8_t *var);
int main()
{
uint8_t string[64] = "-1000.1";
float value = StringToFloat (string);
printf("%f", value);
return 0;
}
float StringToFloat (uint8_t *var)
{
float multiplier;
float result = 0;
bool negative_num = false;
bool found_comma_or_dot = false;
uint16_t numbers_before_dot = 0;
uint16_t numbers_after_dot = 0;
uint16_t i = 0;
while (*(var+i) != 0)
{
if (*(var+i) == '-') { negative_num = true; }
else if (*(var+i) == '.' || *(var+i) == ',') { found_comma_or_dot = true; }
else
{
if (found_comma_or_dot == false) { numbers_before_dot++; }
if (found_comma_or_dot == true) { numbers_after_dot++; }
}
i++;
}
multiplier = pow (10, numbers_before_dot-1);
while (*var != 0)
{
if (*var == '-') { var++; }
if (numbers_before_dot > 0)
{
numbers_before_dot--;
result += ( (*var) - 0x30) * (multiplier);
multiplier /= 10;
}
else if (numbers_after_dot > 0)
{
numbers_after_dot--;
result += ( (*var) - 0x30) * (multiplier);
multiplier /= 10;
}
var++;
}
if (negative_num == true)
{
result *= (-1);
}
return result;
}
A problem is precision. A float is simply not very precise. In order to pass your test cases, change from float to double. This can be seen if you run this code:
float t = 123456789;
printf("%f\n", t);
Your code is very overly complex. Here is a much more slick solution.
double StringToFloat(uint8_t *var)
{
// First check if negative. If it is, just step one step forward
// and treat the rest as a positive number. But remember the sign.
double sign = 1;
if(*var=='-') {
sign = -1;
var++;
}
// Read until either the string terminates or we hit a dot
uint32_t integer_part = 0;
while(*var != 0) {
if(*var == '.' || *var == ',') {
var++;
break;
}
integer_part = 10*integer_part + (*var - '0');
var++;
}
// If we hit the string terminator in previous loop, we will do so
// in the beginning of this loop too. If you think it makes things
// clearer, you can add the boolean found_comma_or_dot to explicitly
// skip this loop.
uint32_t decimal_part = 0;
uint32_t decimal_size = 0;
while(*var != 0) {
decimal_part = 10*decimal_part + (*var - '0');
var++;
decimal_size++;
}
return sign * (integer_part + decimal_part/pow(10, decimal_size));
}
Note that I changed uint16_t to uint32_t because I'm using them in another way. If this is not a viable option for you, you can change them to a floating type, but that may cause loss of precision.
There are reasons for using uint16_t and float, but the you will have to live with the limitations. That's just the way it is.
The problem is that float doesn't have enough precision to represent the number 123456789. We have 123456789 ≥ 2^26; in that range float can only represent multiples of 8.
The error for numbers with decimal point is caused by you treating the decimal point like an additional digit instead of ignoring it. Since the ASCII code for "." is two less than the code for "0", that "." is treated like a digit "-2".
PS. Using 0x30 instead of '0' is very bad style.
PS. Use double instead of float unless you have a very good reason that you can explain clearly why you wouldn't.
I am working on a method in C where I am trying to convert a decimal to its base. I am having trouble with returning a Char*. I still am unsure how to return a pointer. When I compile this code, I get a warning saying
"warning: function returns address of local variable [-Wreturn-local-addr]".
and it has to do with my res character. I am uncertain with why I cannot return res, if it's a char. I don't understand what I am suppose to return if I can't return res. Please help.
//return res;
char reVal(int num)
{
if (num >= 0 && num <= 9)
return (char)(num + '0');
else if(num = 10)
{
return (char)(num - 10 + 'A');
}
else if(num = 11)
{
return (char)(num - 11 + 'B');
}
else if(num = 12)
{
return (char)(num - 12 + 'C');
}
else if(num = 13)
{
return (char)(num - 13 + 'D');
}
else if(num = 14)
{
return (char)(num - 14 + 'E');
}
else if(num = 15)
{
return (char)(num - 15 + 'F');
}
}
// Utility function to reverse a string
void strev(char *str)
{
int len = strlen(str);
int i;
for (i = 0; i < len/2; i++)
{
char temp = str[i];
str[i] = str[len-i-1];
str[len-i-1] = temp;
}
}
char* decToBase(int base, int dec)
{
int index = 0; // Initialize index of result
char res[100]; // Convert input number is given base by repeatedly
// dividing it by base and taking remainder
while (dec > 0)
{
res[index++] = reVal(dec % base);
dec /= base;
}
res[index] = '\0';
// Reverse the result
strev(res);
return res;
int main()
{
char* base = decToBase(16, 248);
}
Regardless, the outcome I want is to have the method return "f8" as the outcome.
In your decToBase() function, the issue it's warning about is the use of char res[500];, which is an array that's allocated on the stack as a local variable. These are all thrown away when the function returns, so if you return a pointer to (or: the address of) the res array, this pointer points to junk on the stack.
You have to find some other way to manage this allocation, and though some might suggest using malloc() to allocate memory from the system, this is probably a bad idea because it's asking for problems with memory leaks.
Better is to pass in the buffer you want it to fill, and use that. Then the caller does the allocation and you don't worry about memory leaks.
char *decToBase(int base, int dec, char *outbuf)
{
int index = 0; // Initialize index of result
// Convert input number is given base by repeatedly
// dividing it by base and taking remainder
while (dec > 0)
{
outbuf[index++] = reVal(dec % base);
dec /= base;
}
outbuf[index] = '\0';
// Reverse the result
strev(outbuf);
return outbuf;
}
and then your main function would look like:
int main()
{
char decbuf[500];
decToBase(16, 248, decbuf);
printf("Buffer is %s\n", decbuf);
}
This is still not super ideal, because your decToBase() function doesn't know how big outbuf is, and overflows are possible, so the experience and/or paranoid programmer will also pass in the size of outbuf so your function knows how much to use.
But that's a step you'll get to later.
My teacher gave us an assignment where we create a function that reads ASCII digit characters and converts them to a number without using any library functions such as atoi. Through some research i came up with this in my own file:
#include <stdio.h>
#include <sttdef.h>
int main() {
char testString[] = "123";
int convertedResult = 0;
int i;
for(i = 0; testString[i] != '\0'; i++){
convertedResult = convertedResult*10 + testString[i] - '0';
printf("%i\n",convertedResult);
if (testString[i] == '\0') {
break;
}
}
return 0;
}
While this works on its own i have to use the main file he gave us to call on this specific function.
char *asciiToInteger(char *inputString, int *integerPtr) {
return inputString;
}
I'm a bit confused as to how to proceed from here? attatched picture is main
#include <stdio.h>
#include <stddef.h>
char * asciiToInteger(char *inputString, int *integerPtr){
int convertedResult =0;
for(int i = 0; inputString[i] != '\0'; i++){
convertedResult = convertedResult*10 + inputString[i] - '0';
}
*integerPtr=convertedResult;
return inputString;
}
int main() {
char testString[] = "123";
int integerPtr;
asciiToInteger(testString, &integerPtr) ;
printf("%d\n",integerPtr);
return 0;
}
Your code has a couple of problems:
It assumes the entire string is digits
It checks for the end of string twice
I think a better implementation would be:
#include <stdio.h>
const char *asciiToInteger(const char *inputString, int *value)
{
int result = 0;
while (isdigit((unsigned int) *inputString))
{
result *= 10;
result += *inputString++ - '0';
}
*value = result;
return inputString;
}
This returns a pointer to the first non-converted character, which might be to the end of string marker if the string is all digits. I added const on the strings of course, since this converter is just reading from the strings.
When you get an assignment like this the first step is to make sure you understand what the function is supposed to do. Your question has no such description so that is the place to start.
From the behavior of the main function it seems to be something like:
If the first character in the input string is not a digit return NULL
If the first character in the input string is a digit convert all leading digits to an integer stored in the object pointed to by integerPtr and return a pointer to the character following the converted digits.
Examples:
inputString = "a123b67" --> return NULL
inputString = "123b67" --> *integerPtr = 123 and return a pointer to the 'b' in the input
That could look something like this:
char *asciiToInteger(char *inputString, int *integerPtr) {
if (*inputString < '0' || *inputString > '9')
return NULL; // no leading digit
*integerPtr = 0;
do
{
*integerPtr = *integerPtr * 10 + *inputString - '0';
++inputString;
} while (*inputString >= '0' && *inputString <= '9');
return inputString;
}
Notice that the code above can't handle negative integers.