Convert char array to int array c++ - c++

I`m having problems converting a char array read from file to an int array. Maybe someone can help me. This is my code:
char vectorPatron[67];
int iPatrones[67];
archivo = fopen("1_0.txt", "r");
for(i=0;i<67;i++){
fscanf(archivo, "%c", &vectorPatron[i]);
printf("%c",vectorPatron[i]);
}
fclose(archivo);
for(i=0;i<67;i++){
iPatrones[i] = atoi(&vectorPatron[i]);
printf("%d",iPatrones[i]);
}

Despite using some C++ features, most of your code looks more like C. Might I recommend something more like:
struct to_int {
int operator()(char c) { return c - '0'; }
};
const int num = 67;
std::vector<char> patrons(num);
std::vector<int> patron_values(num);
std::ifstream archivo("1_0.txt");
archivo.read(&patrons[0], num);
std::cout.write(&patrons[0], num);
std::transform(patrons.begin(), patrons.end(), patron_values.begin(), to_int());
std::copy(patron_values.begin(), patron_values.end(),
std::ostream_iterator<int>(std::cout, "\n"));

That's because atoi receives a null-delimited string, while you are passing it a pointer to a single char (both are essentially char *, but the intent and use are different).
Replace the call to atoi with iPatrons[i] = vectorPatron[i] - '0';
Also, you can remove the vectorPatrons array, simply read into a single char in the first loop and then assign to the appropriate place in the iPatrons array.

I believe you cannot use the atoi function since it needs an string (array of chars terminated by the \0 character). Why dont you simply do:
for(i=0;i<67;i++){
iPatrones[i] = int(vectorPatron[i] - '0');
printf("%d",iPatrones[i]);
}
Note: i do not know how the source file looks like, so maybe the error is there. How exactly are those numbers stored in the file? Maybe you could use (if they are stored as number separated by space):
for(i=0;i<67;i++){
fscanf(archivo, "%d", &iPatron[i]);
}

Here is a very simple and reusable approach. This function converts a char into an int and returns the int. BAD_RETURN = 10 because every single character is from '0' to '9'. The source of this function is cplusplus.com.
int CharToInt(char ch)
{
return((ch >= '0' && ch <= '9') ? ch - '0' : BAD_RETURN);
}
This is my own function that works in VS2015 compiler. Define an int array and initialize it to 0s. Pass this int array along with the its char prototype array into following function. This function converts a char array into an int array using CharToInt function:
void copyCharArrToIntArr(char from[MAX], int to[MAX])
{
for (int i = 0; i < MAX; i++)
to[i] = CharToInt(from[i]);
}
This approach will work with vectors. Instead of MAX, use i < yourVector.size() for the for-loop condition.

Related

Why can't I call my function recursively?

I'm trying to compile this code in order to reverse a string:
void reverse(char *str, int n)
{
if (n==0 || n==1) {
return; //acts as quit
} else {
char i = str[0]; //1st position of string
char j = str[n-1]; //Last position of string
char temp = str[i];
str[i] = str[j]; //Swap
str[j] = temp;
reverse(str[i+1],n-1); // <-- this line
}
}
#include <iostream>
int main()
{
char *word = "hello";
int n = sizeof word;
reverse(word, n);
std::cout << word << std::endl;
return 0;
}
The compiler reports an error where I call reverse() recursively:
invalid conversion from char to char* at reverse(str[i+1], n-1).
Why?
Any advice on other issues in my code is also welcome.
str[i+1] is a character, not a pointer to a character; hence the error message.
When you enter the function, str points to the character you're going to swap with the n:th character away from str.
What you need to do in the recursion is to increment the pointer so it points to the next character.
You also need to decrease n by two, because it should be a distance from str + 1, not from str.
(This is easy to get wrong; see the edit history of this answer for an example.)
You're also using the characters in the strings as indexes into the strings when swapping.
(If you had the input "ab", you would do char temp = str['a']; str['a'] = str['b']; str['b'] = temp;. This is obviously not correct.)
str[0] is not the position of the first character, it is the first character.
Use std::swap if you're allowed to, otherwise see below.
More issues: you shouldn't use sizeof word, as that is either 4 or 8 depending your target architecture - it's equivalent to sizeof(char*).
You should use strlen to find out how long a string is.
Further, you should get a warning for
char *word = "hello";
as that particular conversion is dangerous - "hello" is a const array and modifying it is undefined.
(It would be safe if you never modified the array, but you are, so it isn't.)
Copy it into a non-const array instead:
char word[] = "hello";
and increase the warning level of your compiler.
Here's a fixed version:
void reverse(char *str, int n)
{
if(n <= 1) // Play it safe even with negative n
{
return;
}
else
{
// You could replace this with std::swap(str[0], str[n-1])
char temp = str[0]; //1st character in the string
str[0] = str[n-1]; //Swap
str[n-1] = temp;
// n - 2 is one step closer to str + 1 than n is to str.
reverse(str + 1, n - 2);
}
}
int main()
{
char word[] = "hello";
// sizeof would actually work here, but it's fragile so I prefer strlen.
reverse(word, strlen(word));
std::cout << word << std::endl;
}
I'm going to dissect your code, as if you'd posted over on Code Review. You did ask for other observations, after all...
Firstly,
char *word = "hello";
Your compiler should warn you that pointing a char* at a literal string is undefined behaviour (if not, make sure that you have actually enabled a good set of warnings. Many compilers emit very few warnings by default, for historical reasons). You need to ensure that you have a writable string; for that you can use a char[]:
char word[] = "hello";
The next line
int n = sizeof word;
has now changed meaning, but is still wrong. In your original code, it was the size of a pointer to char, which is unlikely to be the same as the length of the word "hello". With the change to char[], it's now the size of an array of 6 characters, i.e. 6. The sixth character is the NUL that ends the string literal. Instead of the sizeof operator, you probably want to use the strlen() function.
Moving on to reverse():
You read characters from positions in the string, and then use those characters to index it. That's not what you want, and GCC warns against indexing using plain char as it may be signed or unsigned. You just want to index in one place, and your i and j are unnecessary.
Finally, the question you asked. str[i+1] is the character at position i+1, but your function wants a pointer to character, which is simply str+i+1. Or, since we worked out we don't want i in there, just str+1.
Note also that you'll need to subtract 2 from n, not 1, as it will be used as a count of characters from str+1. If you only subtract 1, you'll always be swapping with the last character, and you'll achieve a 'roll' rather than a 'reverse'.
Here's a working version:
void reverse(char *str, int n)
{
if (n < 2)
// end of recursion
return; //acts as quit
char temp = str[0];
str[0] = str[n-1]; //Swap
str[n-1] = temp;
reverse(str+1,n-2);
}
#include <iostream>
#include <cstring>
int main()
{
char word[] = "hello";
int n = std::strlen(word);
reverse(word, n);
std::cout << word << std::endl;
}
We can make further changes. For example, we could use std::swap to express the switching more clearly. And we could pass a pair of pointers instead of a pointer and a length:
#include <utility> // assuming C++11 - else <algorithm>
void reverse(char *str, char *end)
{
if (end <= str)
// end of recursion
return;
std::swap(*str, *end);
reverse(str+1, end-1);
}
and invoke it with reverse(word, word+n-1).
Finally (as I'm not going to mention std::reverse()), here's the idiomatic iterative version:
void reverse(char *str, char *end)
{
while (str < end)
std::swap(*str++, *end--);
}
use like this :
reverse(&str[i+1],n-1);
pass address of the (i+1)th position not value.

Grabbing a portion of a string like substr

So I'm making a function that is similar to SubStr. This is an assignment so I cannot use the actual function to do this. So far I have created a function to take a string and then get the desired substring. My problem is returning the substring. In the function when I do Substring[b] = AString[b]; the substring is empty, but if I cout from inside the function I get the desired substring. So what is wrong with my code?
Here is a working demo: http://ideone.com/4f5IpA
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length);
int main() {
char someString[] = "abcdefg";
char someSubString[] = "";
subsec(someString, someSubString, 1, 3);
cout << someSubString << endl;
return 0;
}
void subsec(char AString[], char Substring[], int start, int length) {
for (int b = start; b <= length; b++) {
Substring[b] = AString[b];
}
}
Maybe this does what you're looking for? It's hard to say as your initial implementation used the length parameter as more of an end position.
#include <iostream>
using namespace std;
void subsec(char AString[], char Substring[], int start, int length)
{
const int end = start + length;
int pos = 0;
for(int b = start; b < end; ++b)
{
Substring[pos++] = AString[b];
}
Substring[pos] = 0;
}
int main()
{
char someString[50] = "abcdefghijklmnopqrstuvwxyz";
char someSubString[50];
subsec(someString, someSubString, 13, 10);
cout << someSubString << endl;
return 0;
}
There are several problems with the code:
1) The char arraysomeSubString has size 1 which cannot hold the substring.
2) The subsec is not correctly implemented, you should copy to the Substring from index 0.
Also remember to add \0 at the end of the substring.
void subsec(char AString[], char *Substring, int start, int length) {
int ii = 0;
for (int jj = start; jj <= length; jj++, ii++) {
Substring[ii] = AString[jj];
}
Substring[ii] = '\0';
}
You need to allocate more than 1 byte for someSubString i.e.
char someSubString[] = "xxxxxxxxxxxxxxxxxx";
or just
char someSubString[100];
if you know the max size you'll ever need.
Either would allocate enough space for the string you're copying to it. Then, you're not doing anything about the terminating 0 either. At the end of a C-style string there needs to be a terminating null to signify end of string. Otherwise cout will print something like;
abcdefgxxxxxxx
if you initialized with x's as I indicated.
There are a few problems with your code as it stands. Firstly, as your compiler is no doubt warning you, in C++ a string literal has type const char[], not just char[].
Secondly, you need to have enough space to store your substring. A good way to do this is for your function to allocate the space it needs, and then pass back a pointer to this memory. This is the way things are typically done in C code. The only thing is that you have to remember to delete the allocated array when you're done with it. (There are other, better ways to do this in C++, with things like smart pointers and wrapper objects, but those come later :-) ).
Thirdly, you'll have a problem if you request a length which is actually longer than the passed-in string -- you'll run off the end and start copying random memory (or just crash), which is definitely not what you want. C strings are terminated with a "nul byte" -- so you need to check whether you've come across this.
Speaking of the nul, you need to make sure that your substring ends with one.
Lastly, it's not really a problem but there's no need for the start parameter, you can just pass a pointer to the middle of the array if you want to.
char* substring(const char* str, int length)
{
// Allocate memory for substring;
char* subs = new char[length+1];
// Copy characters from given string
int i = 0;
while (i < length && str[i] != '\0') {
subs[i] = str[i];
i++;
}
// Append the nul byte
subs[i] = '\0';
return subs;
}
int main()
{
const char someString[] = "foobarbaz"; // Note -- must be const in C++
char* subs = substring(someString + 3, 3);
assert(strcmp(subs, "bar") == 0);
delete subs;
}

Recursive Function Loop Through Character Array

I have an assignment where I'm supposed to loop through a Character Array using a Recursive Function. I figured it would be easy since I would know the length of the array but then the prototype is give to me which I have to use:
void display(char str[])
I can't imagine how I'm supposed to loop through this recursively without knowing the length. Can anybody give me a nudge on this please?
void display(char str[])
{
if (*str) {
putchar(*str);
display(str+1);
}
}
C strings (assuming your character array is a C string) are assumed to be null terminated. So, you could, for instance, use a recursive function to compute the length and look for the null character for your base case to know you are done.
As mentioned by #abelenky and #Nathan, a character array is assumed to end with a "null" char (usually '\0').
Here's an example on how to find the number of characters
unsigned int strLen( const char[] str ) {
unsigned int len = 0;
while( str[len] ) {
len++;
}
return len;
}

Scanning ASCII value of each character of a string

Is there anyway , if I enter any string , then I want to scan ASCII value of each character inside that string , if I enter "john" then I should get 4 variables getting ASCII value of each character, in C or C++
Given a string in C:
char s[] = "john";
or in C++:
std::string s = "john";
s[0] gives the numeric value of the first character, s[1] the second an so on.
If your computer uses an ASCII representation of characters (which it does, unless it's something very unusual), then these values are the ASCII codes. You can display these values numerically:
printf("%d", s[0]); // in C
std::cout << static_cast<int>(s[0]); // in C++
Being an integer type (char), you can also assign these values to variables and perform arithmetic on them, if that's what you want.
I'm not quite sure what you mean by "scan". If you're asking how to iterate over the string to process each character in turn, then in C it's:
for (char const * p = s; *p; ++p) {
// Do something with the character value *p
}
and in (modern) C++:
for (char c : s) {
// Do something with the character value c
}
If you're asking how to read the string as a line of input from the terminal, then in C it's
char s[SOME_SIZE_YOU_HOPE_IS_LARGE_ENOUGH];
fgets(s, sizeof s, stdin);
and in C++ it's
std::string s;
std::cin >> s; // if you want a single word
std::getline(std::cin, s); // if you want a whole line
If you mean something else by "scan", then please clarify.
You can simply get the ascii value of a char by casting it to type int:
char c = 'b';
int i = c; //i contains ascii value of char 'b'
Thus, in your example the code to get the ascii values of a string would look something like this:
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::endl;
int main()
{
string text = "John";
for (int i = 0; i < text.size(); i++)
{
cout << (int)text[i] << endl; //prints corresponding ascii values (one per line)
}
}
To get the corresponding char from an integer representing an entry in the ascii table, you just have to cast the int back to char again:
char c = (char)74 // c contains 'J'
The code given above was written in C++ but it basically works the same way in C (and many other languages as well I guess)
There is no way to turn a string of length 'x' into x variables. In C or C++ you can only declare a fixed number of variables. But probably you don't need to do what you are saying. Perhaps you just need an array, or most likely you just need a better way to solve whatever problem you are trying to solve. If you explain what the problem is in the first place, then I'm sure a better way can be explained.
Ya,I think there are some more better solutions are also available but this one also be helpful.
In C
#include <stdio.h>
#include <string.h>
#include <malloc.h>
int main(){
char s[]="abc";
int cnt=0;
while(1){
if(s[cnt++]==NULL)break;
}
int *a=(int *)malloc(sizeof(int)*cnt);
for(int i=0;i<cnt;i++)a[i]=s[i];
for(int i=0;i<cnt-1;i++)printf("%d\n",a[i]);
return 0;
}
In C++
#include <iostream>
#include <string>
using namespace std;
int main(){
string s="abc";
//int *a=new int[s.length()];
//for(int i=0;i<s.length();i++)a[i]=s[i];
for(int i=0;i<s.length();i++)
cout<<(int)s[i]<<endl;
return 0;
}
I hope this one will be helpful..
yeah it's very easy ..just a demo
int main()
{
char *s="hello";
while(*s!='\0')
{
printf("%c --> %d\n",*s,*s);
s++;
}
return 0;
}
But make sure your machine is supporting the ASCII value format.
In C every char has one integral value associted with it called ASCII.
Using %d format specifier you can directly print the ASCII of any char as above.
NOTE: It's better to get good book and practice this kind of program yourself.

Convert non-null-terminated char* to int

I am working on some code that reads in a data file. The file frequently contains numeric values of various lengths encoded in ASCII that I need to convert to integers. The problem is that they are not null-terminated, which of course causes problems with atoi. The solution I have been using is to manually append a null to the character sequence, and then convert it.
This is the code that I have been using; it works fine, but it seems very kludgy.
char *append_null(const char *chars, const int size)
{
char *tmp = new char[size + 2];
memcpy(tmp, chars, size);
tmp[size + 1] = '\0';
return tmp;
}
int atoi2(const char *chars, const int size)
{
char *tmp = append_null(chars, size);
int result = atoi(tmp);
delete[] tmp;
return result;
}
int main()
{
char *test = new char[20];
test[0] = '1';
test[1] = '2';
test[2] = '3';
test[3] = '4';
cout << atoi2(test, 4) << endl;
}
I am wondering if there is a better way to approach this problem.
Fixed-format integer conversion is still well within handroll range where the library won't do:
size_t mem_tozd_rjzf(const char *buf, size_t len) // digits only
{
int n=0;
while (len--)
n = n*10 + *buf++ - '0';
return n;
}
long mem_told(const char *buf, size_t len) // spaces, sign, digits
{
long n=0, sign=1;
while ( len && isspace(*buf) )
--len, ++buf;
if ( len ) switch(*buf) {
case '-': sign=-1; \
case '+': --len, ++buf;
}
while ( len-- && isdigit(*buf) )
n = n*10 + *buf++ -'0';
return n*sign;
}
In C++11, you can say std::stoi(std::string(chars, size)), all from <string>.
int i = atoi(std::string(chars, size).c_str());
Your method will work, although you should only need size+1 for appending the null and the null will go at position size. Currently, your test code doesn't actually make the function call, but I'll assume that you have a way to determine when the null-terminated characters end. If possibly, I'd recommend making the null termination there so that you don't have to worry about catching cases where you hit an exception before you can deallocate the memory (memory which, honestly, may or may not have been allocated if you start catching exceptions).
std::string str = "1234";
boost::lexical_cast<int>(str); // 1234
The problem as formulated requires to construct a string given an array of known size, then converting its text into a numeric value.
To convert text into values, C++ has a unified mechanism: streams.
In your case, you can do the following:
int i = 0;
std::stringstream(std::string(yourbuffer, yoursize)) >> i;
This will completely avoid any plain old C reference.
But, since -as you say- all values come from a file... why just don't read the file itself as a stream via std::fstream ?
The question says (emph mine):
The file frequently contains numeric values of various lengths encoded
in ASCII that I need to convert to integers. The problem is that they
are not null-terminated, which of course causes problems with atoi.
This does not really pose a problem, as, if we look at the docs for atoi or strtol, they clearly state:
Function discards any whitespace characters until first non-whitespace
character is found. Then it takes as many characters as possible to
form a valid integer number representation and converts them to
integer value.
That means, it doesn't matter at all that the numbers aren't null terminated, as long as they are delimited by something that stops conversion.
And if they are not delimited, then you have to know the size, and when you know the size, I would also recommend a hand-coded solution like in the other answer.
I know this answer is not answering OP's question, but it helps if your source of char* is a char array with known size.
Live demo
#include <fmt/core.h>
#include <type_traits>
#include <iostream>
// SFINAE fallback
template<typename T, typename =
std::enable_if< std::is_pointer<T>::value >
>
int charArrayToInt(const T arr){ // Fall back for user friendly compiler errors
static_assert(false == std::is_pointer<T>::value, "`charArrayToInt()` dosen't allow conversion from pointer!");
return -1;
}
// Valid for both null or non-null-terminated char array
template<size_t sz>
int charArrayToInt(const char(&arr)[sz]){
// It doesn't matter whether it's null terminated or not
std::string str(arr, sz);
return std::stof(str);
}
int main() {
char number[2] = {'4','2'};
int ret = charArrayToInt(number);
fmt::print("The answer is {}. ", ret);
return 0;
}