Build code: "strlwr" by pointer [duplicate] - c++

This question already has answers here:
Why can't I write to a string literal while I *can* write to a string object?
(4 answers)
Closed 8 years ago.
Someone can tell me different between this code:
char *s1 ="Con Chim Non";
and this one:
char *s=new char[100];
gets(s);
Then, I add the word: "Con Chim Non".
After, I build a code that change value of the pointer. In first code, I got a problem about the address. The second is right. And this is my code:
void Strlwr(char *s)
{
if (s == NULL )
return ;
for (int i = 0; s[i] != '\0'; ++i)
{
if ( s[i] <= 'Z' && s[i] >= 'A')
s[i] = s[i]+32;
}
}
And someone can tell me why the first is wrong.

The first example:
char *s1 ="Con Chim Non";
You declare a pointer to a text literal, which is constant. Text literals cannot be modified.
The proper syntax is:
char const * s1 = "Con Chim Non";
Note the const.
In your second example, you are declaring, reserving memory for 100 characters in dynamic memory:
char *s=new char[100];
gets(s);
You are then getting an unknown amount of characters from the input and placing them into the array.
Since you are programming in the C++ language, you should refrain from this kind of text handling and use the safer std::string data type.
For example, the gets function will read an unknown amount of characters from the console into an array. If you declare an array of 4 characters and type in 10, you will have a buffer overflow, which is very bad.
The std::string class will expand as necessary to contain the content. It will also manage memory reallocation.

Related

C++ Pointers to arrays

#include <stdio.h>
char strA[80] = "A string to be used for demonstration purposes";
char strB[80];
char *my_strcpy(char *destination, char *source)
{
char *p = destination;
while (*source != '\0')
{
*p++ = *source++;
}
*p = '\0';
return destination;
}
int main(void)
{
my_strcpy(strB, strA);
puts(strB);
}
so my question here is that when i take out the portion:
//*p= '\0';
it prints the exact same answer, so why is this necessary? from my understanding, \0 is a nul portion of memory after a string but since the array strA already contains the nul portion since its in "" is it really necessary?
It seems you already know the importance of the null terminator, but the point is, you defined char strB[80]; in external namespace (with static life span), which causes initialization of the array strB, which sets all bytes of it to zero. That's why you can't observe the difference (because even if you don't append a null character, the rest of strB already is).
Moving the definition of strB makes this visible. strA doesn't need moving because it doesn't matter.
In actuality, this code
while (*source != '\0')
{
*p++ = *source++;
}
// *p = '\0';
When *source reaches a null character, it's not copied to *p, so you need to manualky add a terminator for that.
Your loop stops when it sees the \0 and so it is not copied to the destination and the destination is not NUL terminated. Is that a problem?
Not if your destination buffer is initialized to all 0s
Not if your code is willing to deal with fixed length strings (so the my_strcpy signature would need to change to return the length)
In general YES - the 0 terminated C string is such a common thing that not following the convention is asking for trouble,
Whether you 0 terminate or not the rest of the values will be the same as they were when you started. The 0 termination just makes your character array a "standard C string".
For arguments sake: Assuming you knew every string had space for 80 chars you could just do
for(int i = 0; i < 80; i++)
{
dest[i] = src[i];
}
The effect is the same and assuming the source is 0 terminated the destination will be too.

C++ tolower/toupper char pointer

Do you guys know why the following code crash during the runtime?
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
I'm trying to lowercase a char* (string). I'm using visual studio.
Thanks
You cannot compare it to NULL. Instead you should be comparing *it to '\0'. Or better yet, use std::string and never worry about it :-)
In summary, when looping over a C-style string. You should be looping until the character you see is a '\0'. The iterator itself will never be NULL, since it is simply pointing a place in the string. The fact that the iterator has a type which can be compared to NULL is an implementation detail that you shouldn't touch directly.
Additionally, you are trying to write to a string literal. Which is a no-no :-).
EDIT:
As noted by #Cheers and hth. - Alf, tolower can break if given negative values. So sadly, we need to add a cast to make sure this won't break if you feed it Latin-1 encoded data or similar.
This should work:
char word[] = "HeLlo";
for (auto it = word; *it != '\0'; ++it) {
*it = tolower(static_cast<unsigned char>(*it));
}
You're setting word to point to the string literal, but literals are read-only, so this results in undefined behavior when you assign to *it. You need to make a copy of it in the dynamically-allocated memory.
char *word = new char[20];
strcpy(word, "HeLlo");
Also in your loop you should compare *it != '\0'. The end of a string is indicated by the character being the null byte, not the pointer being null.
Given code (as I'm writing this):
char* word;
word = new char[20];
word = "HeLlo";
for (auto it = word; it != NULL; it++){
*it = (char) tolower(*it);
This code has Undefined Behavior in 2 distinct ways, and would have UB also in a third way if only the text data was slightly different:
Buffer overrun.
The continuation condition it != NULL will not be false until the pointer it has wrapped around at the end of the address range, if it does.
Modifying read only memory.
The pointer word is set to point to the first char of a string literal, and then the loop iterates over that string and assigns to each char.
Passing possible negative value to tolower.
The char classification functions require a non-negative argument, or else the special value EOF. This works fine with the string "HeLlo" under an assumption of ASCII or unsigned char type. But in general, e.g. with the string "Blåbærsyltetøy", directly passing each char value to tolower will result in negative values being passed; a correct invocation with ch of type char is (char) tolower( (unsigned char)ch ).
Additionally the code has a memory leak, by allocating some memory with new and then just forgetting about it.
A correct way to code the apparent intent:
using Byte = unsigned char;
auto to_lower( char const c )
-> char
{ return Byte( tolower( Byte( c ) ) ); }
// ...
string word = "Hello";
for( char& ch : word ) { ch = to_lower( ch ); }
There are already two nice answers on how to solve your issues using null terminated c-strings and poitners. For the sake of completeness, I propose you an approach using c++ strings:
string word; // instead of char*
//word = new char[20]; // no longuer needed: strings take care for themseves
word = "HeLlo"; // no worry about deallocating previous values: strings take care for themselves
for (auto &it : word) // use of range for, to iterate through all the string elements
it = (char) tolower(it);
Its crashing because you are modifying a string literal.
there is a dedicated functions for this
use
strupr for making string uppercase and strlwr for making the string lower case.
here is an usage example:
char str[ ] = "make me upper";
printf("%s\n",strupr(str));
char str[ ] = "make me lower";
printf("%s\n",strlwr (str));

About pointers and arrays [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
#include<stdio.h>
#include<stdlib.h>
char *syllable[26] = {"a","bub","cash","dud","e","fud","gug","hash","i","jay",
"kuck","lul","mum","nun","o","pub","quack","rug","sus",
"tut","u","vuv","wack","xux","yuck","zug"};
void Tutnese(char *word, char *newword);
char *letter;
void Tutnese(char *word, char *newword)
{
//clrscr();
for(*letter = 'A'; *letter <= 'Z'; *letter++)
{
letter=syllable;
printf("%c\n",&letter);
}
}
Tutnese is an English language game primarily used by children who use it to converse in
(perceived) privacy from adults (or vice versa)
I am trying to let A="A" B="bub" c="cash" and so on.
I am expecting a result like this.
“computer.” becomes “cashomumpubututerug.”
- “Stony” become “Sustutonunyuck”
but i just start learning c, and i have no idea how to use pointer. I've been keep getting error like assignment makes integer from pointer without a cast
char *letter;
This statement declares a variable named letter, same way as any other statement like char ch; will do.
Now, what's the difference then!!
Well the difference (and similarity) is:
char ch; declares a char variable, i.e. a memory block of size 1 byte is allocated (statically), which you can refer to using ch.
char *letter; on the other hand declares a char pointer i.e. a memory size of 2 or 4 or 8 bytes (depending on compiler) will be allocated (again statically) to store address of a char variable.
Now when you use *letter as lvalue (on Left Hand Side) as you do in for loop, this means you are trying to write to the memory address stored in letter. In your case you never stored any address in letter, to do so you can use letter = &ch; where ch is some char variable.
That was all the lecture!!
Now my suggestion for your program:
You don't need to use letter pointer for the loop, a simple char i variable will be fine.
To re-form the string as you plan to, you can simply use the characters of the original string as indices to form new string. Declare a empty string of some large length, then keep concatenating the syllable[orig_string[i] - 'A'], inside a for loop till the end of orig_string. Assumption is orig_string contains all uppercase alphabets
Finally, Correct your printf syntax.
Do read about pointers in C from a good source, as they will never leave you, and will give you all sorts of nightmare.
Code
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *syllable[26] = {"a","bub","cash","dud","e","fud","gug","hash","i","jay",
"kuck","lul","mum","nun","o","pub","quack","rug","sus",
"tut","u","vuv","wack","xux","yuck","zug"};
void Tutnese(char *word, char *newword, size_t new_size);
void Tutnese(char *word, char *newword, size_t new_size)
{
char *end = newword + new_size;
char c;
while ((c = *word++) != '\0')
{
if (!isalpha(c))
*newword++ = c;
else
{
char *tut = syllable[tolower(c) - 'a'];
ptrdiff_t len = strlen(tut);
if (end - newword <= len)
break;
memcpy(newword, tut, len + 1);
newword += len;
}
}
*newword = '\0';
}
int main(void)
{
char i_data[1024];
char o_data[4096];
while (fgets(i_data, sizeof(i_data), stdin) != 0)
{
Tutnese(i_data, o_data, sizeof(o_data));
printf("I: %sO: %s", i_data, o_data);
}
return(0);
}
Output
I: computer
O: cashomumpubututerug
I: how do you tell mum that she cannot understand us?
O: hashowack dudo yuckou tutelullul mumumum tuthashatut sushashe cashanunnunotut ununduderugsustutanundud usus?
I: The quick brown fox jumped over the lazy dog.
O: tuthashe quackuicashkuck bubrugowacknun fudoxux jayumumpubedud ovuverug tuthashe lulazugyuck dudogug.
Lets forget about pointers and break down the problem.
You're given a word word and you want to create newword based on your mapping.
First, you need to figure out how big newword is.
To do that, iterate through the characters in word and add the string lengths of the mappings (call it N)
Once you've done that, you know you can allocate N+1 bytes (strings are null terminated in C) for newword (via malloc).
Then, you iterate through the characters again and just append to newword
Let me give you a few hints:
To iterate through a string (lets call it word), the C code would look like:
unsigned int wordlen = strlen(word);
for(unsigned int index = 0; index < wordlen; index++)
printf("Character at %u is %c", index, word[index]);
Your for loop is quite messed up. Do look up a few tutorials on pointers and string manipulation in C.

how to check const char* values one by one

I have a const char* variable which takes values from a function that I have wrote.
When I write this variable to a file many times it writes nothing. So it must be empty or filled in with space.The strange thing is that in the txt file that I write it changes line every time, when it has value or not.Why is that?Does it mean that the returned value from the function has a \n?
how can I check if a value of a const char * is empty or in general how can I check character by character the value in char*?
Since C/C++ pointers can be interpreted as arrays of values the pointers point to, the two ways of checking values of a char* is by applying an indexing operator or by using pointer arithmetics. You can do this:
const char *p = myFunctionReturningConstChar();
for (int i = 0 ; p[i] ; i++) {
if (p[i] == '\n') printf("New line\n");
}
or this:
const char *p = myFunctionReturningConstChar();
while (*p) {
if (*p == '\n') printf("New line\n");
p++;
}
In addition, C++ library provides multiple functions for working with C strings. You may find strlen helpful to check if your pointer points to an empty string.

Array initialization issue

I need an empty char array, but when i try do thing like this:
char *c;
c = new char [m];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
and then I print c. can see that c = 0x00384900 "НННННННээээ««««««««юоюою"
after cycle it becomes: 0x00384900 "ABCDEFGээээ««««««««юоюою"
How can I solve this problem? Or maybe there is way with string?
If you're trying to create a string, you need to make sure that the character sequence is terminated with the null character \0.
In other words:
char *c;
c = new char [m+1];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
c[m] = '\0';
Without it, functions on strings like printf won't know where the string ends.
printf("%s\n",c); // should work now
If you create a heap array, OS will not initialiase it.
To do so you hvae these options:
Allocate an array statically or globally. The array will be filled with zeroes automatically.
Use ::memset( c, 0, m ); on heap-initialised or stack array to fill it with zeroes.
Use high-level types like std::string.
I believe that's your debugger trying to interpret the string. When using a char array to represent a string in C or C++, you need to include a null byte at the end of the string. So, if you allocate m + 1 characters for c, and then set c[m] = '\0', your debugger should give you the value you are expecting.
If you want a dynamically-allocated string, then the best option is to use the string class from the standard library:
#include <string>
std::string s;
for (i = 0; i < m; i++)
s.push_back(65 + i);
C strings are null terminated. That means that the last character must be a null character ('\0' or just 0).
The functions that manipulate your string use the characters between the beginning of the array (that you passed as parameter, first position in the array) and a null value. If there is no null character in your array the function will iterate pass it's memory until it finds one (memory leak). That's why you got some garbage printed in your example.
When you see a literal constant in your code, like printf("Hello");, it is translate into an array of char of length 6 ('H', 'e', 'l', 'l', 'o' and '\0');
Of course, to avoid such complexity you can use std::string.