Read all the subsequent chars and transform into an int - c

I'm reading a txt file and getting all the chars that aren't space, transforming them to int using (int)c-'0' and that is working.
The problem is if the number has more than 1 digit, because I'm reading char by char.
How could I do to read like a sequence of chars, transform this sequence of chars into int?
I tried using a string, but when I try to pass this string to my other function, it treats each index as a number, but what I need is that the whole string is treated as one number.
Any ideas?

A convenient way to do the conversion is to read the whole number into a buffer (string) and then call atoi. Make triple sure that the string is properly null-terminated.

One solution, I won't say it's good or bad in your case since you don't provide any code, but you could do something like this: (pseudoish code)
int i;
int val = 0;
char *string = "5238785";
for (i = 0; i < strlen(string); i++) {
val = val * 10 + atoi(string[i]);
}
NOTE: I simplified it and you should do more string controls to make sure you don't go out of bounds etc. Make sure the string is NULL-terminated \0, but the concept is that you read one digit at the time, and just move what you've read so far "one step left" to fit next digit.

Related

How to assign first two characters in a string to a variable in C (Arduino)

I have an Arduino project with a string, called string, which is four digits, each between 0 and 9. So for example, a possible value is 1200. I'd like to take the first character, 1, and assign it to another string, called xCo.
String string = String(c);
String xCo = String(string[0]);
Serial.print(xCo);
Strangely, the Serial.print(xCo); line doesn't just print the first character, 1. Rather, it prints the whole string. I've read other questions' answers and they said that to reference a particular character, you just choose the index number of that character by doing something like string[0]. Yet, this isn't working for me.
What am I doing wrong here?
Edit: As the commenters have pointed out, String is an Arduino type, at least I'm pretty sure. My C and Arduino experience is very limited, so I can't be sure.
If you need to get the value of a character at a given position in a string, use charAt().
String string = "1200";
char singleCharacter = string.charAt(0);
Serial.print(singleCharacter);
Lot of people recommends to not use String. The best way is to simply use char *
char *foo = "1200";
char c = foo[0];

Correct way of initializing a non known value String in C

Say I want to create a String that will hold some values based on another string. Basically, I want to be able to compress one string, like this: aaabb -> a3b2 - But my question is:
In Java you could do something like this:
String mystr = "";
String original = "aaabb";
char last = original.charAt(0);
for (int i = 1; i < original.length(); i++) {
// Some code not relevant
mystr += last + "" + count; // Here is my doubt.
}
As you can see, we have initialized an empty string and we can modify it (mystr += last + "" + count;). How can you do that in C?
Unfortunately, in C you cannot have it as easy as in Java: string memory needs dynamic allocation.
There are three common choices here:
Allocate as much as you could possibly need, then trim to size once you are done - This is very common, but it is also risky due to a possibility of buffer overrun when you miscalculate the max
Run your algorithm twice - the first time counting the length, and the second time filling in the data - This may be the most efficient one if the timing is dominated by memory allocation: this approach requires you to allocate only once, and you allocate the precise amount of memory.
Allocate as you go - start with a short string, then use realloc when you need more memory.
I would recommend using the second approach. In your case, you would run through the source string once to compute the compressed length (in your case, that's 5 - four characters for the payload "a3b2", and one for the null terminator. With this information in hand, you allocate five bytes, then use the allocated buffer for the output, which is guaranteed to fit.
In C (not C++) you can do something like this:
char mystr[1024];
char * str = "abcdef";
char c = str[1]; // will get 'b'
int int_num = 100;
sprintf(mystr, "%s%c%d", str, c, int_num);
This will create a string in 'mystr':
"abcdefb100"
You can then concatenate more data to this string using strcat()
strcat(mystr, "xyz"); // now it is "abcdefb100xyz"
Please note that mystr has been declared to be 1024 bytes long and this is all the space you can use in it. If you know how long your string will be you can use malloc() in C to allocate the space and then use it.
C++ has much more robust ways of dealing with strings, if you want to use it.
You can use string concatenation method strcat:
http://www.cplusplus.com/reference/cstring/strcat/
You define your string as following:
char mystr[1024]; // Assuming the maximum string you will need is 1024 including the terminating zero
To convert the character last into a string to be able to concatenate it, you use the following syntax:
char lastString[2];
lastString[0] = last; // Set the current character from the for loop
lastString[1] = '\0'; // Set the null terminator
To convert the count into a string you need to use itoa function as following:
char countString[32];
itoa (count, countString, 10); // Convert count to decimal ascii string
Then you can use strcat as following:
strcat(mystr, lastString);
strcat(mystr, countString);
Another solution is to use STL String class or MFC CString if you are using Visual C++.

Printf Variable String Length Specifier

I have a struct that contains a string and a length:
typedef struct string {
char* data;
size_t len;
} string_t;
Which is all fine and dandy. But, I want to be able to output the contents of this struct using a printf-like function. data may not have a nul terminator (or have it in the wrong place), so I can't just use %s. But the %.*s specifier requires an int, while I have a size_t.
So the question now is, how can I output the string using printf?
Assuming that your string doesn't have any embedded NUL characters in it, you can use the %.*s specifier after casting the size_t to an int:
string_t *s = ...;
printf("The string is: %.*s\n", (int)s->len, s->data);
That's also assuming that your string length is less than INT_MAX. If you have a string longer than INT_MAX, then you have other problems (it will take quite a while to print out 2 billion characters, for one thing).
A simple solution would just be to use unformatted output:
fwrite(x.data, 1, x.len, stdout);
This is actually bad form, since `fwrite` may not write everything, so it should be used in a loop;
for (size_t i, remaining = x.len;
remaining > 0 && (i = fwrite(x.data, 1, remaining, stdout)) > 0;
remaining -= i) {
}
(Edit: fwrite does indeed write the entire requested range on success; looping is not needed.)
Be sure that x.len is no larger than SIZE_T_MAX.
how can I output the string using printf?
In a single call? You can't in any meaningful way, since you say you might have null terminators in strange places. In general, if your buffer might contain unprintable characters, you'll need to figure out how you want to print (or not) those characters when outputting your string. Write a loop, test each character, and print it (or not) as your logic dictates.

Proper use of strcat() in C

I have an archive file that looks like this:
!<arch>
file1.txt/ 1350248044 45503 13036 100660 28 `
hello
this is sample file 1
Now in here, the number 28 in the header is the file1.txt size. To get that number, I use:
int curr_char;
char file_size[10];
int int_file_size;
curr_char = fgetc(arch_file);
while(curr_char != ' '){
strcat(file_size, &curr_char);
curr_char = fgetc(arch_file);
}
// Convert the characters to the corresponding integer value using atoi()
int_file_size = atoi(file_size);
However, values in the file_size array change every time I run my code. Sometimes it's correct, but mostly not. Here are some examples of what I get for file_size:
?28`U
2U8U
28 <--- Correct!
pAi?28
I believe the problem is with my strcat() function, but not sure. Any help would be appreciated.
You shouldn't read the file character wise. There are higher level functions doing this. As larsmans already pointed out, you can use fscanf() for this task:
fscanf(arch_file, "%d", &int_file_size);
&curr_char is an int*, so you're copying over the bits of an int as if they represented a string.
You should be using scanf.
The expression &curr_char points to a single character (well, actually an integer as that's how you declared it). strcat looks for a string, and string as you should know are terminated by a '\0' character. So what strcat does in your case is use the &curr_char pointer as the address of a string and looks for the terminator. Since that is not found weird stuff will happen.
One way of solving this is to make curr_char an array, initialized to zero (the string terminator character) and read into the first entry:
char curr_char[2] = { '\0' }; /* Will make all character in array be zero */
...
curr_char[0] = fgetc(...);
There is also another problem, and that is that you are trying to concatenate into a string that is not initialized. When running your program, the array file_size can contain any data, it's not automatically zeroed out. This leads to the weird characters before the number. This is solved partially the same way as the above problem, by initializing the array:
char file_size[10] = { '\0' };

Trouble understanding how to process C string

I'm trying to use Mac OS X's listxattr C function and turn it into something useful in Python. The man page tells me that the function returns a string buffer, which is a "simple NULL-terminated UTF-8 strings and are returned in arbitrary order. No extra padding is provided between names in the buffer."
In my C file, I have it set up correctly it seems (I hope):
char buffer[size];
res = listxattr("/path/to/file", buffer, size, options);
But when I got to print it, I only get the FIRST attribute ONLY, which was two characters long, even though its size is 25. So then I manually set buffer[3] = 'z' and low and behold when I print buffer again I get the first TWO attributes.
I think I understand what is going on. The buffer is a sequence of NULL-terminated strings, and stops printing as soon as it sees a NULL character. But then how am I supposed to unpack the entire sequence into ALL of the attributes?
I'm new to C and using it to figure out the mechanics of extending Python with C, and ran into this doozy.
char *p = buffer;
get the length with strlen(p). If the length is 0, stop.
process the first chunk.
p = p + length + 1;
back to step 2.
So you guessed pretty much right.
The listxattr function returns a bunch of null-terminated strings packed in next to each other. Since strings (and arrays) in C are just blobs of memory, they don't carry around any extra information with them (such as their length). The convention in C is to use a null character ('\0') to represent the end of a string.
Here's one way to traverse the list, in this case changing it to a comma-separated list.
int i = 0;
for (; i < res; i++)
if (buffer[i] == '\0' && i != res -1) //we're in between strings
buffer[i] = ',';
Of course, you'll want to make these into Python strings rather than just substituting in commas, but that should give you enough to get started.
It looks like listxattr returns the size of the buffer it has filled, so you can use that to help you. Here's an idea:
for(int i=0; i<res-1; i++)
{
if( buffer[i] == 0 )
buffer[i] = ',';
}
Now, instead of being separated by null characters, the attributes are separated by commas.
Actually, since I'm going to send it to Python I don't have to process it C-style after all. Just use the Py_BuildValue passing it the format character s#, which knows what do with it. You'll also need the size.
return Py_BuildValue("s#", buffer, size);
You can process it into a list on Python's end using split('\x00'). I found this after trial and error, but I'm glad to have learned something about C.

Resources