Why it isn't necessary to store null character at the end of the string named temp in the following code
char source[50] = "hello world";
char temp[50] = "anything";
int i = 0;
int j = 0;
while (source[i] != '\0')
{
temp[j] = source[i];
i = i + 1;
j = j + 1;
}
cout << temp; // hello world
while in the case below it becomes necessary
char source[50] = "hello world";
char temp[50];
int i = 0;
int j = 0;
while (source[i] != '\0')
{
temp[j] = source[i];
i = i + 1;
j = j + 1;
}
cout << temp; // will give garbage after hello world
// in order to correct this we need to put temp[j] = '\0' after the loop
The difference is in the way of the definition of temp.
In the first case
char temp[50] = "anything";
temp is initialized. All its elements that was not assigned a character from the string literal were zero initialized.
In the second case
char temp[50];
temp was not initialized so its elements contain any arbitrary values.
There is a third case when temp had static storage duration. In this case if it is defined as
char temp[50];
all its elements are initialized by zero.
For example
#include <iostream>
char temp[50];
int main()
{
char source[50] = "hello world";
int i = 0;
int j = 0;
while (source[i] != '\0')
{
temp[j] = source[i];
i = i + 1;
j = j + 1;
}
std::cout << temp;
}
Also take into account that it would be more safe and effective to use standard C function strcpy to copy source into temp. For example
#include <cstring>
//...
std::strcpy( temp, source );
To add something.. in the definition of temp[] in the first sample you use the following code:
char source[50] = "hello world";
char temp[50] = "anything";
int i = 0;
int j = 0;
You see, the length of source (strlen) is 12, the length of temp is 9.. you also initialized the variable i and j to zero..
The location of i and j variables in the memory are actually right after the temp array.. So, for temp array, at location 12 (at the length of source array) this location has been already initialized to 0 by the definition and declaration of i and j variables.
So, you don't need the temp[j] = '\0' anymore..
Related
so I wrote this code to reverse one of the names based on the user option the idea is to use another function to reverse and to use pointers but after trying all I could think of my code return the same name not changed the best I could do was changing the first letter of the name to a weird sign.
#include <iostream>
using namespace std;
void reverse(char* A) {
int count = 0;
char temp[10];
for (int i = 0; A[i] != NULL; i++)
count++;
for (int i = 0; A[i] != NULL; i++) {
temp[count]=A[i];
count--;
}
for (int i = 0; A[i] != NULL; i++) {
A[i] = temp[i];
}
}
int main(){
int x= 0;
int index;
char Name_list[5][10];
cout << "please enter the names of the student " << endl;
for (int i = 0; i < 5; i++) {
cin >> Name_list[i];
for (int j = 0; Name_list[i][j] != NULL; j++) {
x++;
}
while (x > 10)
{
x = 0;
cout << "you have entered more then the allowed number of characters per name enter another name " << endl;
cin >> Name_list[i];
for (int j = 0; Name_list[i][j] != NULL; j++) {
x++;
}
}
x = 0;
}
for (int i = 0; i < 5; i++) {
cout << Name_list[i] << endl;
}
cout << "please enter the index of the name you want to reverse" << endl;
cin >> index;
while (index>4||index <0)
{
cout << "you entered incorrect index please enter a number from 0 to 4 " << endl;
}
reverse(Name_list[index]);
for (int i = 0; i < 5; i++) {
cout << Name_list[i] << endl;
}
system("pause");
}
For starters such a function should return a pointer to the result string. That is it should be declared like
char * reverse( char *s );
Note: do not use variable names consisting from upper case letters.
The type int can be not large enough to store length of a string. Instead use the type size_t.
char * reverse( char *s )
{
size_t count = 0;
//...
It is totally unclear why there is present an array with the number of elements equal to the magic number 10
char temp[10];
To reverse a string there is no need to declare an auxiliary array. Such an approach is principally wrong.
In this for loop
for (int i = 0; A[i] != NULL; i++)
there is compared an object of the type char with the pointer NULL. The compiler should issue a message for such a wrong comparison. It seems you mean
for (int i = 0; A[i] != '\0'; i++)
In any case the introduced variable i in this first for loop is redundant because you already has the variable count.
As you have the array temp with the fixed size equal to 10 then the both loops after the first loop can invoke undefined behavior even if the length of the source string is equal exactly to 10.
And the result string is not zero terminated.
The function can look the following way.
char * reverse( char *s )
{
size_t count = 0;
while ( s[count] ) ++count;
for ( size_t i = 0; i < count / 2; i++ )
{
char c = s[i];
s[i] = s[count - i - 1];
s[count - i - 1] = c;
}
return s;
}
Or using standard functions you could write the function reverse the following way
#include <utility>
#include <cstring>
//...
char * reverse( char *s )
{
for ( size_t i = 0, n = std::strlen( s ); i < n / 2; i++ )
{
std::swap( s[i], s[n-i-1] );
}
return s;
}
Pay attention to that there is the standard algorithm std::reverse. Using it you could reverse a string the following way
std::reverse( s, s + std::strlen( s ) );
for (int i = 0; A[i] != NULL; i++) {
temp[count]=A[i];
count--;
}
If i goes up from 0 to 5, count goes down from 6 to 1.
Ok, a few things.
If you want do some string manipulation, look into the stdlib. Unless you are doing this for class.
Your writing everything to the end of the temp. buffer
You need to add an extra character at the end of the strings for the null byte (I think this implementation may allow for a seg. fault)
I wrote a swap funtion to swap two c'style strings in cpp,before the swap operation.
I can cout the first line of a 2 dimension string s[2][27] correctly,but i swaped s[0] with s[1], I tried to cout s[0] and the compiler gave me a segmentation fault.
void swap1(char *a, char *b)
{
char *temp;
int i = 0, j = 0;
while (a[i] != '\0')
{
temp[j] = a[i];
i++;
j++;
}
temp[j] = '\0';
i = 0, j = 0;
while (b[i] != '\0')
{
a[j] = b[i];
i++, j++;
}
a[j] = '\0';
i = 0, j = 0;
while (temp[i] != '\0')
{
b[j] = temp[i];
i++, j++;
}
b[j] = '\0';
}
int main()
{
char s[2][27] = {"wangzhehan", "cuisibo"};
// const char s[2][10]={"111","222"};
cout << s[0] << endl;//s[0] can be printed correctly
swap1(s[0], s[1]);
cout << s[0];//the compiler showed a segmentation fault here
the expected result is
wangzhehan
cuisibo
but in fact the result is
wangzhehan
then the compiler showed"Exception has occurred.
Segmentation fault"
or,is there a better way to swap two string using no standard library function?
When swapping the two strings, you don't need to store a temporary string as a whole.
(or you will have to rely on dynamic allocation)
In your code you declare char *temp; and right after you use temp[j] but this temporary string is not allocated (the pointer points towards anything).
I won't give here the complete solution, since it looks like an exercise, but only
this suggestion.
Use a single loop, in which you place a[i] in a temporary char (not char *),
then move b[i] to a[i] and finally move the temporary char to b[i].
(you will have to take care of the length of the two strings when swapping the characters)
You did not allocate memory where you are going temporary to copy strings. The pointer temp is not initialized.
char *temp;
So the function invokes undefined behavior.
The function can be written simpler if to use standard C string functions.
For example
#include <iostream>
#include <cstring>
#include <algorithm>
void swap1( char *a, char *b )
{
size_t n = std::max( strlen( a ), strlen( b ) ) + 1;
char *temp = new char[n];
std::strcpy( temp, a );
std::strcpy( a, b );
std::strcpy( b, temp );
delete [] temp;
}
int main()
{
char s[2][27] = {"wangzhehan", "cuisibo"};
std::cout << s[0] << '\n';
swap1( s[0], s[1] );
std::cout << s[0] << '\n';
return 0;
}
The program output is
wangzhehan
cuisibo
If you is not allowed to use standard string functions and must to use only loops then the function can look the following way as it is shown in the demonstrative program below.
#include <iostream>
void swap1( char *a, char *b )
{
size_t n1 = 0;
while( a[n1] != '\0' ) ++n1;
size_t n2 = 0;
while ( b[n2] != '\0' ) ++n2;
size_t n = n1 < n2 ? n2 : n1;
char *temp = new char[n + 1];
for ( size_t i = 0; ( temp[i] = a[i] ) != '\0'; ++i );
for ( size_t i = 0; ( a[i] = b[i] ) != '\0'; ++i );
for ( size_t i = 0; ( b[i] = temp[i] ) != '\0'; ++i );
delete [] temp;
}
int main()
{
char s[2][27] = {"wangzhehan", "cuisibo"};
std::cout << s[0] << '\n';
swap1( s[0], s[1] );
std::cout << s[0] << '\n';
return 0;
}
Again the function output is
wangzhehan
cuisibo
And at last the most simplest way is to declare the function as a template function. In this case you need not to allocate memory dynamically.
For example
#include <iostream>
template <size_t N>
void swap1( char ( &a )[N], char ( &b )[N] )
{
char temp[N];
for ( size_t i = 0; ( temp[i] = a[i] ) != '\0'; ++i );
for ( size_t i = 0; ( a[i] = b[i] ) != '\0'; ++i );
for ( size_t i = 0; ( b[i] = temp[i] ) != '\0'; ++i );
}
int main()
{
char s[2][27] = {"wangzhehan", "cuisibo"};
std::cout << s[0] << '\n';
swap1( s[0], s[1] );
std::cout << s[0] << '\n';
return 0;
}
The code:
char *temp;
[...]
temp[j] = a[i];
stores a[i] at whatever address is on stack at the moment (understand to non allocated memory). This will crash. If you need to swap something to a temporary, first allocate your temporary to the size of the minimum string's length.
Please notice that your code is a very bad idea.
The function signature expects two pointer to a char array. It does not say what is the array length. Provided the string will not be the same length, you can't swap the string safely (since the array size for the second parameter can be shorter than the first parameter's array size).
If you really want to reinvent the wheel, you'd do something like this:
void swap(char *& s1, char *& s2) { char * tmp = s2; s2 = s1; s1 = tmp; }
int main()
{
char * s[2] = {"wangzhehan", "cuisibo"};
cout << s[0] << endl;//s[0] can be printed correctly
swap(s[0], s[1]);
cout << s[0];
My Code example:
char* array = new char[10];
char* str;
int j = 0;
MyClass(char* input){ //input = sentence columns terminated by '\n'
str = new char[strlen(input)];
for(int i=0; i<strlen(input); i++){
if (input[i] == '\n'){ //look for end of line
str[i] = '\0'; //add \0 Terminator for char[]
array[j] = &(str[i]); //store address of sentence beginning in array
j++;
}
else{
str[i] = input[i];
}
}
}
How do i store an address into an array. So i can get the beginning address of a sentence by number. I created a solution with a vector storing my sentences as char* objects. But there must be a way without vectors?!
EDIT:
This is my solution.
#include <iostream>
using namespace std;
class Pointer{
public:
char** array = new char*[10];
char* str;
char* buffer;
int j = 1;
Pointer(char* input){
str = new char[strlen(input)];
array[0] = str;
for (int i = 0; i < strlen(input); i++){
if (input[i] == '\n'){
str[i] = '\0';
array[j] = &(str[i]) + sizeof(char);
j++;
}
else{
str[i] = input[i];
}
}
}
void output(int i){
buffer = array[i];
cout<<buffer;
}
};
Thanks for your help! :)
The best way would be to use std containers for that (std::vector<std::string>). Anyway, if you do need to have it the C way:
In this line:
array[j] = &(str[i]);
you are storing an address of ith character of the string. If you want to store the pointer to entire string, use:
array[j] = str;
Please note you have numerous other errors in your code.
For example, you should not be using a constant size array for that, as you're risking undefined behaviour in case you have more lines in your text.
Btw. MyClass is a function, not a class.
Answer to actual question:
char ** array = new (char *)[10];
What you should probably do instead:
std::vector<std::string> array;
char* array[10]
char* str;
int j = 0;
MyClass(char* input){ //input = sentence columns terminated by '\n'
str = new char[strlen(input)];
for(int i=0; i<strlen(input); i++){
if (input[i] == '\n'){ //look for end of line
str[i] = '\0'; //add \0 Terminator for char[]
array[j] = str; //store address of sentence beginning in array
// or you can use
// array[j] = &(str[0]);
j++;
}
else{
str[i] = input[i];
}
}
}
Hope it helps!
class Pointer{
public:
Pointer(std::string input){
addresses = split(input, '\n', addresses);
}
void output(int i){
std::cout << addresses.at(i);
}
private:
std::vector<std::string> addresses;
};
Sorry if this seems really noobish and all, and the fact is, i've only been studying this for about a month now. I can't seem to get this to work right, wondering if any of you can help me out. The program once compiled only says that the inputted words are "not palindrome" even if they are.
#include <iostream>
#include <cstring>
#include <string>
using namespace std;
bool isPal (char[], int);
int main ()
{
const int size = 10;
int flag = 0;
char arr[size];
cout << "Enter Word\n";
cin.getline(arr,10);
flag = isPal(arr, size);
if (flag == true)
cout << "Word is Palindrome\n";
else
cout << "Not Palindrome\n";
return 0;
}
bool isPal (char arr [],int size)
{
int q = 0;
char arr2[size];
for (int i = 0;i < size - 1; i++)
{
arr2[i] = arr[9 - q]; //here I attempt to reverse arr1 and assign each element to arr2
q++;
}
for (int j = 0; j < size - 1; j++)
{
if (arr [j] != arr2[j])
return false;
}
return true
}
If you only want to use plain C arrays then check with below code:-
bool isPallindrome ( char *p, int size ) //Remember here size must be one character before null //terminator.
{
char *begin, *end;
begin = p;
end = p + size;
while ( begin != end )
{
if( *begin != *end )
break;
begin++;
end--;
}
if ( begin != end )
return false;
return true;
}
Initialize the arr2
Use strlen to know the length you Input rather than use size, because your input data is not always fixed in 10
In your original code:
input: 1234567
*arr => "1234567\0"
*arr2 => "??\07654321"
Use size replaced by q
bool isPal (char arr [],int size)
{
//q=0; /* modified 3 */
char arr2[size] = ""; /* modified 1 */
for (int i=0; i<strlen(arr); i++) /* modified 2 */
{
arr2[i] = arr[strlen(arr)-i-1]; /* modified 2 */
//q++; /* modified 3 */
}
for (int i=0; i<strlen(arr); i++) /* modified 2 */
{
if (arr[i] != arr2[i])
return false;
}
return true
}
Array is "a pointer point to begin of array address", But for newbie, it's not easy to know how it works. You can reserve this thread until you learn the chapter pointer
Following the example of modified original code:
char arr[size];
char arr2[size];
// char *parr = (char*)malloc(sizeof(char)*size);
// char *parr2 = (char*)malloc(sizeof(char)*size);
cin.getline(arr,10);
// parr = &arr[0];
// cin.getline(parr, 10);
arr2[i] = arr[9 - q];
// parr1 = &arr[9-q];
// parr2 = &arr2[i]
// *parr2 = *parr1;
if (arr [j] != arr2[j])
// parr1 = &arr[j]
// parr2 = &arr2[j]
// if (*parr1 != *parr2)
This was the interview question:
How to convert Dogs like cats to cats like Dogs ?
My code shows: cats like cats. Where am I making the mistakes?
#include <iostream>
using namespace std;
int main()
{
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--)
{
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--)
{
str[words] = reverse[m];
words++;
}
}
}
cout << str;
return 0;
}
I know you can do this using pointers, stack, vectors... but interviewer was not interested in that!
This is a fixed version of your sample code:
Your principal problem is that every time you found and ' ' or '\0' you copy the bytes of the reverse string from the beginning to that point. Example in loop 5 you copy from index 0-5 (stac) from reverse to str in reverse order, but in in loop 10 you copy from index 0-10 (stac ekil) from reverse to str in reverse order, until here you have already the printed result string ('cats like cats'), and the same in loop 15 all of this incrementing the index of str, in the last loop you are written pass the end of the valid memory of str (and because of that not printed as output).
You need to keep track when end the last word reversed to reverse only the actual word, and not the string from the beginning to the actual index.
You don't want to count the special character (' ' and '\0') in the reversing of the words, you would end with cats like\0dogs
Modified sample code provided:
#include <iostream>
using namespace std;
int main() {
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
// change here added last_l to track the end of the last word reversed, moved
// the check of the end condition to the end of loop body for handling the \0
// case
for (int l = 0, last_l = 0; ; l++) {
if (reverse[l] == ' ' || reverse[l] == '\0')
{
for (int m = l - 1; m >= last_l; m--) { // change here, using last_t to
str[words] = reverse[m]; // only reverse the last word
words++; // without the split character
}
last_l = l + 1; // update the end of the last
// word reversed
str[words] = reverse[l]; // copy the split character
words++;
}
if (reverse[l] == '\0') // break the loop
break;
}
cout << str << endl;
return 0;
}
Some code, written with the restriction of using the most simple features of the language.
#include <iostream>
// reverse any block of text.
void reverse(char* left, char* right) {
while (left < right) {
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main() {
char sentence[] = "dogs like cats";
std::cout << sentence << std::endl;
// The same length calculation as sample code.
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
std::cout << len << std::endl;
// reverse all the text (ex: 'stac ekil sgod')
reverse(sentence, sentence + len - 1);
// reverse word by word.
char* end = sentence;
char* begin = sentence;
while (end < sentence + len) {
if (*end != ' ')
end++;
if (end == sentence + len || *end == ' ') {
reverse(begin, end - 1);
begin = end + 1;
end = begin;
}
}
std::cout << sentence << std::endl;
return 0;
}
Dissecting your algorithm in pieces. First, you find the length of the string, not including the null char terminator. This is correct, though could be simplified.
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
This could easily be written simply as:
size_t len = 0;
while (sentence[len])
++len;
Next, you reverse the entire string, but the first defect surfaces. The VLA (variable length array) you declare here, (which you don't need and shouldn't use, as it is a C++ extension and non-standard) does not account for, nor set, a terminating null-char.
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
This temporary buffer string is not needed at all. There is no reason you can't do this entire operation in-place. Once we calculate len correctly, you simply do something like the following to reverse the entire sequence, which retains the null char terminator in proper position:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
Next we move to where you try to reverse each internal word. Again, just as before, the buffer length is not correct. It should be len+1. Worse (hard to imagine), you never remember where you left off when finding the end point of a word. That location should be the next point you start checking for, and skipping, whitespace. Without retaining that you copy from current point all the way back to the beginning of the string. which essentially blasts cats over dogs.
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
Once again, this can be done in-place without difficulty at all. One such algorithm looks like this (and notice the loop that reverses the actual word is not-coincidentally the same algorithm as reversing our entire buffer):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
Putting It All Together
Though considerably simpler to use pointers than all these index variables, the following will do what you're attempting, in place.
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
Output
dogs like cats
cats like dogs
My advise would be to break up the original string into an array of words, reverse that array. Then add those words to your reversed sentence with a space in between.
Since they asked for no libraries, I assumed no std::string, no vectors, nothing at all and so I wrote it in C.. the only thing used is printf. Everything else is from scratch :l
The idea is that you reverse the array first. Then split the array by space and reverse each word.
Example: http://ideone.com/io6Bh9
Code:
#include <stdio.h>
int strlen(const char* s)
{
int l = 0;
while (*s++) ++l;
return l;
}
void reverse(char* str)
{
int i = 0, j = strlen(str) - 1;
for(; i < j; ++i, --j)
{
str[i] ^= str[j];
str[j] ^= str[i];
str[i] ^= str[j];
}
}
void nulltok(char* str, char tok, int* parts)
{
int i = 0, len = strlen(str);
*parts = 1;
for (; i < len; ++i)
{
if (str[i] == tok)
{
str[i] = '\0';
++(*parts);
}
}
}
char* reverse_sentence(char* str)
{
char* tmp = str;
reverse(str);
int i = 0, parts = 0, len = strlen(str);
nulltok(str, 0x20, &parts);
while(parts--)
{
reverse(str);
str += strlen(str) + 1;
}
for(; i < len; ++i)
if (tmp[i] == '\0')
tmp[i] = 0x20;
return tmp;
}
int main(void)
{
char str[] = "dogs like cats";
printf("%s", reverse_sentence(str));
return 0;
}
My solution
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cout<<"enter the sentence"<<endl;
getline(cin,str);
char* pch;
pch = strtok((char*)str.c_str()," ");
string rev = "";
while(NULL != pch)
{
rev.insert(0,pch);
rev.insert(0," ");
pch = strtok(NULL," ");
}
cout<<"the reversed string is :"<<rev<<endl;
return 0;
}