Why does c-string length matter when using for loops? Is there an issue with the termination character '\0'?
The following code sends the for loop into a crazy loop that crashes the compiler:
#include <iostream>
#include<cstring>
using namespace std;
int main()
{
char c[] = "charac";
int i;
for (i=0; i < 8 ; i++)
{
cout << c[i] << endl;
}
return 0;
}
By adding a 't' to my c-string, the code runs perfectly fine:
char c[] = "charact";
int i;
for (i=0; i < 8 ; i++)
{
cout << c[i] << endl;
}
In your first version, there is no character c[7]. You have 7 characters in the array, 6 characters of string and 1 null terminator:
Array: c h a r a c \0
Indices: 0 1 2 3 4 5 6
Attempting to access anything beyond that is undefined behavior.
In your second version, assuming the code you're running has the t you forgot to put in the posted version, the array has 8 characters, and the loop stays within the bounds of the array.
You have a string of length 7 (6 + null terminator), and are attempting to access an 8th element. This will result in undefined behavior.
I think that you are stepping past the end of the end of your character array. By adding the extra character, your string is now 7 characters long so the i<8 test works.
You are index past the end of the array. C starts indexing at zero so the last index of a six character string is five. If you include the null terminator then you have six but you are accessing the seventh array position.
c[7] doesn't exist for "charac" as c[6] is the null terminating character. But when you change it to "charact" then c[7] becomes the null terminating character so it runs fine.
Related
I have trouble understanding the following code,
static char s[N][N];
int i = 0;
while( gets(s[i]) )
{ some loop, where i gets incremented }
considering the array is of N dimensions, then what happens when
gets(s)
is called? How can it store the entire string in the s[i] element? It feels like s[i] should be equal to the first char of the input, and not the entire string. And what happens when it loops with more input? The point is to have it stored as
[char, char, char, char]
[char, char, char, char, char]
[char, char, char, char, char, char]
... and so forth
which it seems like the code is currently doing. But I don't understand how.
EDIT #1
A lot of people suggested against using gets(), but why would gets() not be appropriate when there can be no illegal input and I want to store the characters as elements in an array and not as a string?
The s[i] element is an array of characters since s is an array of arrays. An array of characters can be used to store a string by using a zero character (called a "nul") to mark the end.
The code above is storing the string but with a numbered index.
But storing that number index in the first dimension of the array.
Think of it in this way, I want to store 10 strings of max size of 256 char:
int main()
{
char s[10][256];
for (int i = 0; i < 10; i++ ) {
gets(s[i]);
}
for (int i = 0; i < 10; i++ ) {
cout << s[i] << endl;
}
}
cout << s[1][2] << endl;
Note: for the last line in the code above it would output the second entry (we ordered everything from 0-9) and third character of the string at that entry.
Thus, if my entry was test2 then the output would be 's'.
Note: It would be incorrect to call gets(s) as it will not compile and is not the intention of the code.
gets() call has some features that can land you into a buffer overflow problem if the input is not monitored.
Example:
int multi_array[2][2] = {{2,3,4},
{7,8,9},
{1,5,0}};
Array[n][m]
Gets
First position Array[0][0]
Second position Array[0][1]
Position 0,1 is 3
Position 1,2 is 9
Position 2,2, is 0
`
The asked program was to input two string and print their respective size as first line in output while the second line contains the concatenation of two string and the third line of output contains the original string after the first character of both the string have been swapped..below is my code..everything is working except while printing the second string it is printing unnecessary characters because of which entire second string is not being printed
PS: i'm new to c++
int main()
{
string a,b,c;
cin>>a>>b;
int j=a.size();
int k=b.size();
char s[j],p[k];
cout<<a.size()<<" "<<b.size()<<endl;
c=a+b;
cout<<c<<endl;
for(int i=0;i<a.size();i++)
{
s[i]=a[i];
}
for(int i=0;i<b.size();i++)
{
p[i]=b[i];
}
char t;
t=s[0];
s[0]=p[0];
p[0]=t;
cout<<s<<" ";
cout<<p;
return 0;
}`
input:
dlxecxsye
bfjoosgukxgywz
output:
9 14
dlxecxsyebfjoosgukxgywz
blxecxsye
# dfjoosgukxgywz
desired output:
9 14
dlxecxsyebfjoosgukxgywz
blxecxsye dfjoosgukxgywz
Your string p is of size k, which is size of input b (14).
In your for cycle you iterate from 0 to size of input a (9), which in your case is smaller than size of input b.
When you output content of p at the end of your code, chars at indexes from 9 to 13 are not set and you print something undesired from that place in a memory.
I don't understand the need for the character arrays.
// Swapping first characters
char temp = a[0];
b[0] = a[0];
a[0] = temp;
Please use the debugger and verify that your character arrays are terminated by a nul character.
See also: std::string::c_str() and strncpy.
I need help removing spaces and special characters from an char array.The problem I keep running into is that the erase function only works on string datatypes, if I'm not mistaken. The assignment calls for a char array not a string so I cant just convert it or have a string variable. I've tried looking it up but everything kind of just suggests to convert it to a string or start off as a string, which I can't do. I'm new to programming and pointers are a little weird to me so if the answer is obvious I am sorry.
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
int main()
{
const int SIZE = 80;
char str[SIZE];
char* strPtr;
int strlength;
int j = 0;
int front = 0, back; int flag = 1;
strPtr = str;
cout << "This program checks for palidromes." << endl;
cout << "Please enter a phrase." << endl;
cout << endl;
cin.getline(str, SIZE);
//Get the length of string str
strlength = strlen(str);
//Convert all the characters in the string str to uppercase
for (int i = 0; i < strlength; i++)
{
if (!isupper(str[i]))
str[i] = toupper(str[i]);
}
//Remove all the special characters except letters a - z
for (int i = 0; i < strlength; i++)
if (!isalpha(str[i])||(!isalnum(str[i])))
{
str.erase(str[i]); // need help here. Not sure how to go about it.
}
//str[j] = '\0';
return 0;
}
char* tail = std::remove_if(str, str + strlength,
[](char c){ return !isalpha(c)||(!isalnum(c)); });
strlength = tail - str;
*tail = 0;
The other answer correctly points you to std::remove_if, but I suspect that you really want to understand how to implement the removal yourself, instead of dumping the problem on the C++ library. Also your own attempt at this converts all remaining characters to uppercase, which the other answer does not do.
This is actually simpler than you might think. The relevant bits are as follows:
char *p=str, *q=str;
while (*p)
{
if (isalpha(*p))
*q++=toupper(*p);
++p;
}
*q='\0';
For starters, there's no need to compute strlen() of this string. Simply iterating a pointer from the beginning of the string to the end, until it's pointing at the terminating '\0' is sufficient.
That would be the p pointer. p starts at the beginning of the string, and each iteration of the while loop increments it, with the while loop stopping at the \0.
Then, if p's character is alphabetic, it gets copied to the q pointer, converting it to uppercase, and advancing the q pointer too.
As such, only alphabetic characters get copied to q, everything else gets skipped.
q starts off pointing to the same buffer as p, the buffer with the string. If the string begins with alphabetic characters, the only thing that will happen is that each character gets copied on top of itself, with both p and q advancing together. As soon as p sees a non-alphabetic character, it continues to advance, but q is "left behind", and will continue to accumulate only any remaining alphabetic characters. And when everything is done, the '\0' gets written to q, terminating the new uppercase-only string.
The only real difficult part of this is understanding why everything must occur exactly in the sequence; i.e. the alphabetic character must be copied before p gets incremented, etc... Talk to your rubber duck, if you do not understand why, your rubber duck will explain it to you.
I am trying to implement this code which takes Morse code with 3 spaces between each letter and gets the first Morse translation and compares it to an array containing all Morse code translations. Where it goes buffer == morsem[j], the buffer should equal .- and morsem[j] should also equal .-; if j = 0, which they both do, but it is not executing if's block. Any idea why?
#include <iostream>
using namespace std;
int main(){
char morsem[26][5] = {{".-"},{"-..."},{"-.-."},{"-.."},{"."},{"..-."},{"--."},{"...."},{".."},{".---"},{"-.-"},{".-.."},{"--"},{"-."},{"---"},{".--."},{"--.-"},{".-."},{"..."},{"-"},{"..-"},{"...-"},{".--"},{"-..-"},{"-.--"},{"--.."}};
char alpha[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char morse[] = ".- ....";
int length;
int first_counter = 0;
while(morse[first_counter] != '\0'){
first_counter++;
}
char *new_morse = new char [first_counter];
int counter = 0;
char *buffer = new char [5];
for(int x = 0; x < first_counter; x++){
if(morse[x] != ' '){
buffer[counter] = morse[x];
counter++;
}
if(morse[x] == ' '&& morse[x+1] == ' ' && morse[x+2] == ' '){
for(int j=0;j<27;j++){
if(buffer == morsem[j]){
cout << alpha[j] << endl;
break;
}
}
for(int i = 0; i < first_counter; i++){
new_morse[i] = morse[i+x+3];
}
}
}
delete[] buffer;
cout << morse << endl;
cout << new_morse << endl;
}
if(buffer == morsem[j]){ is just comparing pointer values and not strings. You need to compare "what the pointers are pointing at".
Since you are in C++, using std::string may be easier than char char buffers...
if(buffer == morsem[j]), you are just comparing addresses not the content of the address. Use string type than array of character.
You have undefined behaviour in your program, and the fact that your string comparison is wrong only shadows this (more serious) problem.
char *buffer = new char [5];
This creates a dynamic array with 5 char elements somewhere in memory, and gives you a pointer to the first of those five elements. Unlike with the static morsem array, the elements of the dynamic array created here are not initialised. That is, you must not expect them to contain '\0' values.
Unlike with string literals, there is also no null terminator added automatically. That means when you write ".-" somewhere in your code, then your compiler treats this as an array with 3 elements: '.', '-' and '\0'. With dynamic allocation, no such thing happens.
Now, in the following part of your code:
if(morse[x] != ' '){
buffer[counter] = morse[x];
counter++;
}
counter can be 5. But an attempt to access buffer[5] is undefined behaviour. Since you created buffer as a char[5], the only valid indices are 0, 1, 2, 3 and 4. Your program can do anything, including crashing or randomly working fine.
We then have the wrong string comparison:
if(buffer == morsem[j]){
The problem is that this is no string comparison. You are comparing two pointer values for equality. Use strcmp instead.
Now, once you use strcmp, the uninitialised buffer becomes relevant. strcmp requires both arguments to be null-terminated strings. But your code does not guarantee that buffer[4] is '\0'. This is again undefined behaviour. You probably don't notice it because morsem[j] is null-terminated, and your implementation's strcmp is nice to enough to just stop any comparison as soon as '\0' is found in any of the two strings. But that's not a clean solution.
So, in summary, in order to fix all of those problems:
Understand that the highest index accessible in an array with N elements is N - 1.
Understand that allocating a dynamic char array leaves you with uninitialised elements and no automatically added '\0'.
Use strcmp to compare two char arrays lexicographically.
You should also compile with highest warning levels and activate all run-time checks your compiler offers. For example, try the /MDd option with Visual C++. It will give you a nice crash (just that the button labels may not be German on your system :)):
Needless to say that in real code you just use std::string and forget all these pointer headaches.
You're using a lot of pointers and I do not see the point (pun not intended). It often leads to confusions and misunderstandings. Personally I'd suggest to avoid using them unless necessary. It's the main problem here because it's comparing pointed to values. Try using the Visual Studio debugger (if you're using Visual Studio) to flush it out. Your use of chars is logical, but be aware that the same result can be achieved with string.
A few things.
When I declare my struct with a member array of size 3, wouldn't that mean that array has 4 elements? 0, 1, 2, 3? Why them, when I try to insert the characters A, B, and C, it tells me initializer-string for array of chars is too long [-fpermissive]?
#include <iostream>
using namespace std;
struct Student {
double no;
char grade[3];
};
int main() {
struct Student harry = {975, "ABC"};
}
When I print the address of a specific index of a character array I get the following results from the following code:
struct Student {
double no;
char grade[4];
};
int main() {
struct Student harry = {975, "ABC"};
for (int i = 0; i < 4; i++)
cout << "h.g[" << i << "]" << harry.grade[i] << endl;
for (int i = 0; i < 4; i++)
cout << "h.g[" << i << "]" << &harry.grade[i] << endl;
}
Results:
h.g[0]A
h.g[1]B
h.g[2]C
h.g[3]
&h.g[0]ABC
&h.g[1]BC
&h.g[2]C
&h.g[3]
Why does the first index print ABC, and then BC, and so forth instead of each character separately like the first loop?
No, declaring an array like T arr[3] gives you an array with 3 elements, not 4. The 3 in the declaration is the size of the array. Indices start at 0, so the indices for the elements are 0, 1, and 2.
The string literal "ABC" gives you an "array of 4 const char" where the last element is the null character. Your program is ill-formed if you attempt to initialise an array with a string literal that has too many characters:
There shall not be more initializers than there are array elements.
In the first loop you are getting each character of the array and printing it out. When you print a char you get only that char as output.
When you take the address of an element of the array, with &harry.grade[i], you get a char*. When you output a char*, the I/O library treats it as a C-style null-terminated string. It will output from that character to the first null character it finds. That's why you get the character at position i and the characters following it.
When I declare my struct with a member array of size 3, wouldn't that mean that array has 4 elements? 0, 1, 2, 3?
No, it means it has three elements, which you can access with indices 0,1,2.
Why does the first index print ABC, and then BC, and so forth instead of each character separately like the first loop?
You are accessing beyond the bound of an array, which leads to undefined behaviour. That means anything could happen. You are also assigning a size-4 character array, "ABC", to a size-3 array. So you have out of bonds read and write access.
The 4th element in char array "ABC" it the null-termination \0. When you print the address of any element of a char[N] with std::cout, it will see a char*, which it interprets as a null-terminated string. So it will print characters up to the null termination. So if you print from the beginning, you get A, b, C. If you print from the second element you get B,C, and so on.