Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2

    Errors in Palindrome C++/CLI Program


    Hello,

    So I'm on the last exercise for Chapter 4 of Ivor Horton's book on Beginner Visual C++, and I think my logic thus far is fine, though now looking back, it might have one additional step with copying the array, but ah well heh.

    Anyway, so the program has an initial pointer to character array that contains 5 strings, all of which I have to determine if they are palindromes aka if they are the same phrases forwards AS THEY ARE BACKWARDS.

    Classic Ex: Racecar

    So, my logic goes as follows. I figured I would make a for loop that would iterate through each element of that pointer to character array containing the strings in question.

    I would check to see if the current element of the array is a space, comma, or period, and disregard it by simply incrementing the current value of i by one to skip to the next element.

    I then made an else statement that would catch any characters that are okay by these standards, and then convert them to lowercase to prevent case issues later on into a new array called copy_array.

    Before I actually proceed to actually look at the forwards and reverse forms of the copy_array in the code, I wanted to clear up some compiler errors I received. I will go through each error I received after I post the code, as to attempt to know where I went wrong and also be specific to anyone who would like to help me out.

    Here's my code:

    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    // Here are strings that are possible palindromes, and the known ones from what
    // I can see without the program even running include the madam one, Lid off a 
    // daffodil, and the cigar one: 
    
    	// I made a pointer to character array to possibly analyze each character
    	// inside a given string later on:
    
    	char* string_array[5] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
    							  "Lid off a daffodil.", "Red lost soldier.", 
    							  "Cigar? Toss it in a can. It is so tragic."};
    
    	// Declare the copy char* copy_array:
    
    	char* copy_array[5];
    
    	// Examine each string with a for loop
    
    	for(int i = 0; i < string_array->Length; i++)
    	{
    
    		// Output the string
    
    		Console::WriteLine(L"Here is the current element of string_array: {0}", string_array[i]);
    		
    		// Determine if the string in question aka string_array[i] is a palidrome
    
    		// Maybe I should utilize a function that will literally reverse the 
    		// characters
    
    		// Make an if statement that will test to see if the current element of
    		// string_array is a palindrome
    
    		// I also have to make it rip the punctuation out of the sentence and ignore
    		// spaces
    
    		// I thought maybe to use strcmp() function, but that would just compare
    		// the strings based on alphabetical order
    
    		// strspn(): this function searches a string for the first character that is 
    		// NOT contained in a given set and return the index of the character found
    
    		// Maybe I would make a duplicate array that would copy the phrases from
    		// the string_array and then I should compare the two arrays using the 
    		// strspn() function
    
    		// This would be an okay idea, but I still need to rip out the empty spaces
    		// and format the whole thing to lowercase to remove case-sensitive problems
    		// too
    
    		// Good ideas, continue reviewing string functions on p. 240
    
    		// Let's create a copy of the entire array, that will not contain
    		// periods, commas, or spaces AND make it lower case
    
    		for(int i = 0; i < copy_array->Length; i++)
    		{	
    
    			// Make an if statement that will check to see if the current character
    			// is a period, comma, or space, and IF SO, skip to the next element:
    
    			if (string_array[i] == "." || string_array[i] == "," 
    				|| string_array == " ")
    			{
    				// Increment to the next value of i:
    
    				i++;
    
    			}
    
    			// Make an else statement that will occur if the current character
    			// of the string_array isn't a form of punctuation, and force it to be 
    			// a lowercase form without punctuation and add the current element
    			// to the array:
    			else
    			{
    				copy_array[i] = tolower(string_array[i]);
    
    			}
    
    
    		}
    
    		// Before I move on, I want to fix the errors that are present so at least
    		// I would know that the array was properly copied.
    	}
        return 0;
    }

    Alright, the first error I have is on line 42, and it concerns the fact that I'm misusing the ->Length property, which probably can't be applied to pointer to character arrays:

    Code:
    .\Chapt4_Exercise6.cpp(42) : error C2227: left of '->Length' must point to class/struct/union/generic type
            type is 'char *[5]'
    The second error on line 47 states how I'm misusing the Console::WriteLine command, and that I'm overloading it with arguments so I might need to change this to just Console::Write or find out how to print a current value of a pointer to character array:

    Code:
    .\Chapt4_Exercise6.cpp(47) : error C2665: 'System::Console::WriteLine' : none of the 19 overloads could convert all the argument types
    AND this error associated with line 47 that I have no idea what it is referring to, but probably with how I can't print the pointer to character array using WriteLine:

    Code:
            c:\windows\microsoft.net\framework\v2.0.50727\mscorlib.dll: or       'void System::Console::WriteLine(System::String ^,...cli::array<Type,dimension> ^)'

    The third error is on Line 79 about the misuse of the ->Length property :
    Code:
    .\Chapt4_Exercise6.cpp(79) : error C2227: left of '->Length' must point to class/struct/union/generic type
    The fourth error is about the if statements that are checking to see if the current element of string_array is a space, comma, or period on line 86:

    Code:
    .\Chapt4_Exercise6.cpp(86) : error C2446: '==' : no conversion from 'const char *' to 'char **'
    The fifth error is something I have no idea what it is talking about, but probably my use the of the double equals signs on line 86:

    Code:
    .\Chapt4_Exercise6.cpp(86) : error C2040: '==' : 'char *[5]' differs in levels of indirection from 'const char [2]'
    The sixth error is how I'm using the tolower() function improperly on line 100:

    Code:
    .\Chapt4_Exercise6.cpp(100) : error C2664: 'tolower' : cannot convert parameter 1 from 'char *' to 'int'
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    What kind of object is Length a property of? Also, arrays are not objects, so they cannot have any properties.

    Part of reading and writing code for comprehension means that when you write something it must make sense. Applying an object property to a non-object does not make any sense. Stop and think about what you are trying to say.

    You already know the length of the two arrays, because you declared them: the length is 5. In C, we would normally #define a macro with that information, so that if that value should change then we only need to make that change in one place; eg:
    Code:
    #define  ARRAY_SIZE  5
    
     //  . . . 
    
        char* string_array[ARRAY_SIZE] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
                                  "Lid off a daffodil.", "Red lost soldier.", 
                                  "Cigar? Toss it in a can. It is so tragic."};
    
        // Declare the copy char* copy_array:
    
        char* copy_array[ARRAY_SIZE];
    
        // Examine each string with a for loop
    
        for(int i = 0; i < ARRAY_SIZE; i++)
        {
    You could do the same thing in C++ -- it works just fine -- , but C++ pedantics very much prefer using a const declaration. That way, your const gets type-checked and you don't accidentally write nonsense (macro expansion simply inserts the definition wherever the macro name is encountered, which could cause some syntax and logic errors if you're not careful). Eg:
    Code:
    const int ArraySize = 5;
    
     //  . . . 
    
        char* string_array[ArraySize] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
                                  "Lid off a daffodil.", "Red lost soldier.", 
                                  "Cigar? Toss it in a can. It is so tragic."};
    
        // Declare the copy char* copy_array:
    
        char* copy_array[ArraySize];
    
        // Examine each string with a for loop
    
        for(int i = 0; i < ArraySize; i++)
        {
    You can use a const in this manner in C++, but not in C. You should be able to find discussion of this C++ feature and practice in your book.

    I'm not up on .NET, having only played a bit with C# a bit more than a year ago. If WriteLine can't handle a char*, then I doubt very much that Write could. Have you considered creating a String object out of that char*? I'm hazy on the syntax, but something like String(string_array[i])? -- those here with more .NET experience can verify or correct that.


    Code:
                // Make an if statement that will check to see if the current character
                // is a period, comma, or space, and IF SO, skip to the next element:
    
                if (string_array[i] == "." || string_array[i] == "," 
                    || string_array == " ")
                {
    That is just plain hosed. You're getting the error because you left out the subscript in the third term (look at it and ask yourself where its [i] is), but I can guarantee that that if statement will never ever be true. Do you have any idea what you are saying there? Apparently not!

    Each element in string_array is a string, or rather a char pointer which contains the memory address of the literal strings that were created elsewhere, usually in read-only memory (still in RAM, but in a memory space that's been classified as read-only, so you have no write privileges there). Furthermore, you've created other literal strings in that same read-only memory space: ".", ",", and " ". What you are testing for equality are not the contents of those strings, but rather the memory addresses of those strings. The strings pointed to in string_array are not at the same memory locations of those test strings; obviously not because they are entirely different strings. So your test will never ever succeed.

    Write for comprehension! Understand what it is that you are saying! Remember the old adage (so old that it was used in a 1980's movie, "Short Circuit"): Computers don't do what you want them to do, but only what you tell them to do. You need to understand what you are telling the computer to do.

    That i for-loop is iterating through each string in the string array. Your code says that it wants to test the individual characters of each string in that array. That means that you need another for-loop to iterate through the characters of each string. Furthermore, you need to test the characters against character literals. Double quotes are used for strings, whereas single quotes are used for individual characters; never confuse the two! IOW you want to test against '.', ',', and ' ', which are characters, not strings.

    When you get the embedded loop for iterating through the individual characters of each string, then the error with tolower should clear up: it expects a character whereas you were trying to feed it a pointer.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Originally Posted by dwise1_aol
    What kind of object is Length a property of? Also, arrays are not objects, so they cannot have any properties.

    Part of reading and writing code for comprehension means that when you write something it must make sense. Applying an object property to a non-object does not make any sense. Stop and think about what you are trying to say.

    You already know the length of the two arrays, because you declared them: the length is 5. In C, we would normally #define a macro with that information, so that if that value should change then we only need to make that change in one place; eg:
    Code:
    #define  ARRAY_SIZE  5
    
     //  . . . 
    
        char* string_array[ARRAY_SIZE] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
                                  "Lid off a daffodil.", "Red lost soldier.", 
                                  "Cigar? Toss it in a can. It is so tragic."};
    
        // Declare the copy char* copy_array:
    
        char* copy_array[ARRAY_SIZE];
    
        // Examine each string with a for loop
    
        for(int i = 0; i < ARRAY_SIZE; i++)
        {
    You could do the same thing in C++ -- it works just fine -- , but C++ pedantics very much prefer using a const declaration. That way, your const gets type-checked and you don't accidentally write nonsense (macro expansion simply inserts the definition wherever the macro name is encountered, which could cause some syntax and logic errors if you're not careful). Eg:
    Code:
    const int ArraySize = 5;
    
     //  . . . 
    
        char* string_array[ArraySize] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
                                  "Lid off a daffodil.", "Red lost soldier.", 
                                  "Cigar? Toss it in a can. It is so tragic."};
    
        // Declare the copy char* copy_array:
    
        char* copy_array[ArraySize];
    
        // Examine each string with a for loop
    
        for(int i = 0; i < ArraySize; i++)
        {
    You can use a const in this manner in C++, but not in C. You should be able to find discussion of this C++ feature and practice in your book.

    I'm not up on .NET, having only played a bit with C# a bit more than a year ago. If WriteLine can't handle a char*, then I doubt very much that Write could. Have you considered creating a String object out of that char*? I'm hazy on the syntax, but something like String(string_array[i])? -- those here with more .NET experience can verify or correct that.


    Code:
                // Make an if statement that will check to see if the current character
                // is a period, comma, or space, and IF SO, skip to the next element:
    
                if (string_array[i] == "." || string_array[i] == "," 
                    || string_array == " ")
                {
    That is just plain hosed. You're getting the error because you left out the subscript in the third term (look at it and ask yourself where its [i] is), but I can guarantee that that if statement will never ever be true. Do you have any idea what you are saying there? Apparently not!

    Each element in string_array is a string, or rather a char pointer which contains the memory address of the literal strings that were created elsewhere, usually in read-only memory (still in RAM, but in a memory space that's been classified as read-only, so you have no write privileges there). Furthermore, you've created other literal strings in that same read-only memory space: ".", ",", and " ". What you are testing for equality are not the contents of those strings, but rather the memory addresses of those strings. The strings pointed to in string_array are not at the same memory locations of those test strings; obviously not because they are entirely different strings. So your test will never ever succeed.

    Write for comprehension! Understand what it is that you are saying! Remember the old adage (so old that it was used in a 1980's movie, "Short Circuit"): Computers don't do what you want them to do, but only what you tell them to do. You need to understand what you are telling the computer to do.

    That i for-loop is iterating through each string in the string array. Your code says that it wants to test the individual characters of each string in that array. That means that you need another for-loop to iterate through the characters of each string. Furthermore, you need to test the characters against character literals. Double quotes are used for strings, whereas single quotes are used for individual characters; never confuse the two! IOW you want to test against '.', ',', and ' ', which are characters, not strings.

    When you get the embedded loop for iterating through the individual characters of each string, then the error with tolower should clear up: it expects a character whereas you were trying to feed it a pointer.
    Great ideas, and I can't believe I forgot that [i] in the actual loop.

    Good points overall, I'll definitely review these tomorrow when I go through C++ tomorrow, and at least make a day's attempt at it on my own before posting again.

    Thanks a bunch for helping out, just wanted to say that real quick before I do this tomorrow.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    So this is what I came up with. So far I only have two errors to deal with.

    I made the embedded for loop to access each character of the string in question, and then made an if statement that will check to see if the current character is NOT an alphabetical character, and if so, the loop will skip to the next element.

    I added an else clause that will check each character that passed the previous test, and will assign the current lowercase form of the character to a new array called copy_array.

    Here's my code, and I'll specify the errors with the exact line number afterwards:

    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    // Here are strings that are possible palindromes, and the known ones from what
    // I can see without the program even running include the madam one, Lid off a 
    // daffodil, and the cigar one: 
    
    	// I made a pointer to character array to possibly analyze each character
    	// inside a given string later on:
    
    	// Create a constant integer to use for the size of the array
    	// like dwiseowl said, plus this would make it consistent throughout
    	// the program (good idea):
    
    	const int array_size = 5;
    
    	// Each element in string_array is a string, or rather a char 
    	// pointer which contains the memory address of the literal strings 
    	// that were created elsewhere
    
    	// These memory addresses are in a read-only part of the RAM
    
    	char* string_array[array_size] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
    							  "Lid off a daffodil.", "Red lost soldier.", 
    							  "Cigar? Toss it in a can. It is so tragic."};
    
    	// Declare the copy char* copy_array:
    
    	char* copy_array[array_size];
    
    	// Examine each string with a for loop]
    
    	// Change the conditional to be less than 5 instead of the length
    	// of the entire array
    
    	for(int i = 0; i < array_size; i++)
    	{
    
    		// Output the string
    		// Determine if the string in question aka string_array[i] is a palidrome
    
    		// Maybe I should utilize a function that will literally reverse the 
    		// characters
    
    		// Make an if statement that will test to see if the current element of
    		// string_array is a palindrome
    
    		// I also have to make it rip the punctuation out of the sentence and ignore
    		// spaces
    
    		// I thought maybe to use strcmp() function, but that would just compare
    		// the strings based on alphabetical order
    
    		// strspn(): this function searches a string for the first character that is 
    		// NOT contained in a given set and return the index of the character found
    
    		// Maybe I would make a duplicate array that would copy the phrases from
    		// the string_array and then I should compare the two arrays using the 
    		// strspn() function
    
    		// This would be an okay idea, but I still need to rip out the empty spaces
    		// and format the whole thing to lowercase to remove case-sensitive problems
    		// too
    
    		// Good ideas, continue reviewing string functions on p. 240
    
    		// Let's create a copy of the entire array, that will not contain
    		// periods, commas, or spaces AND make it lower case
    
    		for(int i = 0; i < array_size; i++)
    		{	
    
    			// Make an if statement that will check to see if the current character
    			// is a period, comma, or space, and IF SO, skip to the next element:
    
    			// I've created other literal strings in THE SAME READ-ONLY RAM
    
    			// The following statement will test for quality, and tests the MEMORY 
    			// ADDRESSES of those strings, not the contents of the strings
    
    			// The strings that contain these punctuation marks contain different 
    			// memory addresses than the strings inside the string_array
    
    			// Hence this logic will never succeed
    
    			// What I'm thinking now, is to possibly ditch the idea of 
    			// using pointer to chars, because for whatever reason, I decided
    			// to use them without really understanding that they will point
    			// to memory addresses that contain that value
    
    			// Exactly, why compare memory addresses when I want to look at
    			// SPECIFIC values... Ugh, the logic is so flawed
    
    			// Now that we're checking each STRING inside the string_array
    			// we have to look at individual characters now, so i'm going
    			// to use a for loop with j as its incrementing variable to
    			// really nail the fact that this is a two dimensional array:
    
    			for(int j = 0; j < array_size; j++)
    			{
    				// Double quotes are used for strings 
    				// Single quotes are used for individual characters
    
    				// Make a series of if statements that will look at
    				// spaces, commas, and periods
    
    				// Alright, I think I might have gotten it, let's use the
    				// IsLetter from the Character class in C++/CLI to our 
    				// advantage. That way, whenever an element that is NOT a letter 
    				// aka punctuation is examined, then it will skip to the next
    				// element
    
    				// Old if loop that tried to use IsLetter from the Character
    				// Class in the sense that if the current character of the
    				// string_array being examined WAS NOT A LETTER, then the element
    				// would be skipped:
    
    				// if(!(Char::IsLetter(string_array[j])))
    
    				// 'isalpha' cannot convert the parameter from char* to int...
    				if (!isalpha(string_array[j]))
    				{
    					// If the current character is equal to a space, comma, 
    					// or period, skip to the next character 
    					j++;
    				}
    
    				// Make an else statement that will catch any known characters
    				// that don't match a space, comma, or period:
    
    				else
    				{
    					// Store the current character of string_array into the
    					// copy_array:
    
    					// Also, use the tolower() function in order to convert
    					// the current character into a lowercase letter to prevent 
    					// case-sensitive issues
    
    					copy_array[j] = tolower(string_array[j]);
    
    
    				}
    
    			}
    	
    		}
    
    		// Before I move on, I want to fix the errors that are present so at least
    		// I would know that the array was properly copied.
    	}
        return 0;
    }

    Error 1 on Line 135 specifies how I cannot convert the parameter I passed in, aka the current character from pointer to character and change it into an integer... Maybe its in how I wrote it, for I'm just trying to tell the computer, "Hey look at this element in the second dimension of the array aka on the character level, and if this is NOT an alphabetical character, I want you to skip to the next element please" (lol, I hope telling the computer off will make it not so stubborn heh):

    Code:
    .\Chapt4_Exercise6.cpp(135) : error C2664: 'isalpha' : cannot convert parameter 1 from 'char *' to 'int'
    Error 2 on Line 154 states that I can't convert the current pointer to character element to int, so the error is in how I wrote it.

    I want the computer to assign the current element within string_array's array aka the current character to the current element of the copy_array:

    Code:
    .\Chapt4_Exercise6.cpp(154) : error C2664: 'tolower' : cannot convert parameter 1 from 'char *' to 'int'
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    Originally Posted by HauntJemimah
    I made the embedded for loop to access each character of the string in question,
    No, you did not. Not even close.
    Originally Posted by HauntJemimah
    Error 1 on Line 135 specifies how I cannot convert the parameter I passed in, aka the current character from pointer to character and change it into an integer... Maybe its in how I wrote it, for I'm just trying to tell the computer, "Hey look at this element in the second dimension of the array aka on the character level, and if this is NOT an alphabetical character, I want you to skip to the next element please" (lol, I hope telling the computer off will make it not so stubborn heh):

    Code:
    .\Chapt4_Exercise6.cpp(135) : error C2664: 'isalpha' : cannot convert parameter 1 from 'char *' to 'int'
    Error 2 on Line 154 states that I can't convert the current pointer to character element to int, so the error is in how I wrote it.

    I want the computer to assign the current element within string_array's array aka the current character to the current element of the copy_array:

    Code:
    .\Chapt4_Exercise6.cpp(154) : error C2664: 'tolower' : cannot convert parameter 1 from 'char *' to 'int'
    I already told you the answer on this one, though apparently not directly enough. Here, I'll emphasize it:
    Originally Posted by dwise1_aol
    When you get the embedded loop for iterating through the individual characters of each string, then the error with tolower should clear up: it expects a character whereas you were trying to feed it a pointer.
    Do you understand what is meant by "iterating through the individual characters of each string"? That is what you are supposed to be doing with that inner loop on j, but which you are not doing. Don't you understand why you needed to add that inner loop?

    Here again are the pertinent parts of your code (ellipses inserted):
    Code:
        char* string_array[array_size] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
                                  "Lid off a daffodil.", "Red lost soldier.", 
                                  "Cigar? Toss it in a can. It is so tragic."};
    
        // Declare the copy char* copy_array:
    
        char* copy_array[array_size];
    
      . . . 
     
             for(int i = 0; i < array_size; i++)
            {   
    
      . . . 
    
                for(int j = 0; j < array_size; j++)
                {
    
      . . . 
    
                    // 'isalpha' cannot convert the parameter from char* to int...
                    if (!isalpha(string_array[j]))
    
      . . . 
    
                        copy_array[j] = tolower(string_array[j]);
    Both string_array and copy_array are the same datatype. No problem with that, but you really do need to understand what that datatype is. Let's first concentrate on string_array, since your attempt to use copy_array is completely wrong for what you want to do.

    What is string_array's datatype? It is an array of char pointers. Do you understand that? Do you understand what that means? That means that each element of the array is a char pointer.

    So what is the datatype of string_array[j]? I just told you the answer. The answer is that it is a char pointer; it points to a C-style string that resides elsewhere.

    Is a char pointer the same thing as a char? No, it is not! Which is what the compiler keeps telling you when you try to foist a char pointer onto a function (isalpha and tolower) that expects a char.

    What you need to do is to access each individual character within each string. Which by a really odd coincidence is what I was talking about when I said, "iterating through the individual characters of each string".

    What is a char pointer in C? Isn't it mostly equivalent to a char array? And isn't a char array what a C-style string is? And can't you index into a char array in order to access an individual char? Think about that, because that is what you need to do.

    Are you familiar with two-dimensional arrays? Are you aware that in C a two-dimensional array is equivalent to an array of arrays? So:
    • string_array is an array of char*, AKA a char**.
    • string_array[i] is a char*, which is an array of char.
    • Therefore, string_array[i][j] is a single char. QED.


    Which brings us to your misuse of that inner loop. You want the outer loop to iterate from one string to the next. And you want the inner loop to iterate through all the characters within each string. Wait, I already told you that! Are you going to listen this time?

    Iterate the outer loop for the length of string_array. Iterate the inner loop for the length of the current string, AKA string_array[i]. And in order to access an individual character, use both the i and the j indices, since that individual character effectively resides within a two-dimensional array.

    This is why you need to understand exactly what you saying to the compiler. And why you need to understand how the data is organized. That is why I emphasize that comprehension so much, because you absolutely need it.

    Now for copy_array:
    Code:
                        copy_array[j] = tolower(string_array[j]);
    What does that do? OK, first, let's remove the tolower in order to get directly to what the assignment to copy_array[j] does:

    Code:
                        copy_array[j] = string_array[j];
    What is string_array's datatype? As I pointed out above, it is the same as string_array, which is an array of char pointers.

    So what is the datatype of copy_array[j]? Just like string_array[j], it is a char pointer; it points to a C-style string that resides elsewhere.

    So what does that assignment statement do? It takes the char pointer value in string_array[j] and stores a copy of that address in copy_array[j], which is what the assignment operator does. So for j==0, string_array[j] points to the string in read-only memory, "Madam I'm Adam.", and after the assignment statement has executed then copy_array[j] points to the exact same string at that exact same memory address.

    Is that what you want to do? I believe not. I believe that you want to store a modified copy of the string that string_array[j] points to into memory that copy_array[j] points to. Let me repeat that description of the intended operation: store a modified copy of the string that string_array[j] points to into memory that copy_array[j] points to.

    Now, would this work as your program stands?
    Code:
                        copy_array[i][j] = tolower(string_array[i][j]);
    The answer is "No!". If you're very lucky, it will cause your program to crash. If you are very unlucky, it won't crash and you won't realize how terribly hosed your program is.

    In that code, string_array[i] is the pointer to the string. But where does copy_array[i] point? We have absolutely no idea whatsoever! Why? Because copy_array[i] is an uninitialized pointer!. So before you even begin to consider thinking about using copy_array, you'd better initialize its pointers. Like with new (since you're using C++). Using the lengths of each corresponding string in string_array. And remembering to add an extra character to the length for the null-terminator.

    I've given you more than enough to complete the task.

    Think about what you need to do, what you need to tell the compiler in order to do it, and what your code actually means.
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    Since you were having problems with different levels of indirection (eg, char* vs char), let me recommend this two-part magazine article, Pointer Power in C and C++, Parts 1 and 2 by Christopher Skelly, The C Users Journal, Feb and Mar 1993.

    According to the author's description, he based the article on his experience teaching the subject matter for ten years. Much of it is based on visualizing what it means to go up and down through different levels of pointers and dereferencing, as well as the techniques that you use to go up and down levels of indirection.

    If your college/university library has that magazine in its periodicals section, then burn a copy for yourself. If not, then by Google'ing on "Pointer Power in C and C++" "Christopher Skelly" for other options. I found the articles re-posted at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 1) and at http://collaboration.cmc.ec.gc.ca/sc...lly/skelly.htm (Part 2).

    Another very excellent reference for C that I can recommend is the Schaum Outlines' Programming in C by Byron Gottfried. Chapter 10 is on pointers. At the end of that chapter, pages 323 and 324, there's a list of 20 different kinds of pointer declarations with explanations of exactly what's being declared. That alone is worth the price of the book ($16.95 US), though the rest of the book is also a very good reference, especially the chapter on arrays, which should help greatly in learning to visualize what's going on. Even though it's for C and you're doing C++, the material on arrays and pointers applies equally to both languages.

    Share and enjoy!
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Ah cool, thanks so much for breaking it down.

    I think I just suck at pointers honestly. I get their purpose on how they save memory in functioning programs, but they can be sort of confusing at times for me for some weird reason.

    Usually in the context of the book I have, he used pointers to reference a value in the memory space, and modified it to not only change the pointer's value but the variable that it referenced as well.

    Also, I understand the difference between a pointer and a reference in the sense that if you change the value of a reference, it will not directly change the variable it "references", yet when you do the same thing to a pointer, it will change that original variable it points to.

    I tried maybe thinking to ditch the idea of using pointer to characters because I just obviously have no idea what I'm doing with them, and shouldn't try to copy pasta some format if I don't even know the basics.

    Maybe I should just use string or character arrays because it seemed simpler lol...

    This is good though, because I didn't want to move further in the book until I nailed stupid **** like this early on, so thanks for hitting the points home.

    After really reading your points, I feel maybe that I should just use a character array to access the characters, and ditch the idea of using pointers.

    I'll read that pointer article you sent me, maybe that might give me motivation to use them again in this context though.
    Last edited by HauntJemimah; October 18th, 2013 at 11:32 AM.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Wow, after reading the first part and taking notes, I must admit, I knew jack **** about pointers.

    Wow... haha.

    I'll continue with reading the 2nd part of the article and taking notes on it tomorrow.
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    So after reading the article, I learned a lot though, the explanation on the very last example had my mind reeling (everything else was pretty straight forward up to that point but I tried)

    Anyway, so I'm trying to put the same example inside Visual Studio 2008 in a C++/CLI console program, but am having trouble with the array syntax.

    I know the last array is a pointer to char array but I'm not sure about the over arching arrays. Do we assume that they are just arrays that contain arrays and the only pointer to char array is the final array, ap[]?

    Anyway, here's my code thus far, pretty much what the author has, and I'll add my **** ton of extra notes later but I didn't include them as to not make too much clutter.

    The main problem is with the use of brackets I believe, please help.

    Here's my code:

    Code:
    // Chapter4_PointerPower.cpp : main project file.
    
    #include "stdafx.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    	// Create the pointer to char array that the author has:
    	*char pppp[ppp [app[ap["INTEGER", "PROPORTION", "DEBUGGER", "PORTABLE", "TOWER"]]]]
    
    	// First example in the article:
    	printf("%.*s", 2, *--**pppp);
    
    	// Second example in the article: 
    	printf("%.*s", 3, *(++*pppp[0] - 4)); 
    
    	// Third Example (incomplete... the author didn't include a printf statement 
    	// before it)
    	printf("%.*s",(++*--*++pppp[0] + 5))
    
    	// Fourth Example:
    	printf("%.*s", 2, *++pppp[0][3] + 3); 
    
    	// Fifth Example:
    	printf("%s\n", (*pppp + 2)[-2][2] + 2);
    
    
        return 0;
    }
    I'm basing it off the diagram that was in the article:

    http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/1993/9303/skelly/fig1.htm
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Alright, so I made a diagram just like in that awesome article you sent me.

    I did read it, took a bunch of notes, and as I said, I only had issues with the very last example, because the explanation becomes a little bit convoluted in the first two paragraphs (otherwise, its really obvious that he was going to rip the WER! from the last pointer to character array, "TOWER!")

    So, just like the article did and like you said, literally, draw it out to figure it out!

    So I nutted up and drew it up really quick in photoshop, and tried to explain the for loops.

    [IMG][/IMG]



    Also, I tried reasoning within my code at the for loop in which we examine pointers that are pointing to specific characters in the pointer to character array that we are looking at.

    My problem is that I don't understand the third for loop (so its probably my fault for including a third one). The first for loop goes through each of the pointer to character arrays. The second for loop goes through of the pointers that point to specific characters WITHIN that pointer to character array.

    Also, I took out the if and else clause, because they don't take integer arguments anyway when dealing with pointer to characters so why use them if I don't even know how to use them in this context. I'll add them in later, once I know how to use tolower() for pointer to character arrays (or find the equivalent of it).

    I tried to reason that, since this is dealing with two levels of indirection, I would use the * indirection operator to tell the program to go two levels down, and look at that given pointer to character, and then copy that same pointer to character in the copy_array.

    The issue is with the syntax, which I obviously suck at. This is the line I am talking about:

    Code:
    **copy_array = **string_array;
    Here is my code thus far, I feel like I understand it more... but at the same time, wish I could still implement some form of the isalpha() function to remove non-alphabetical characters from being examined:

    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    // Here are strings that are possible palindromes, and the known ones from what
    // I can see without the program even running include the madam one, Lid off a 
    // daffodil, and the cigar one: 
    
    	// I made a pointer to character array to possibly analyze each character
    	// inside a given string later on:
    
    	// Create a constant integer to use for the size of the array
    	// like dwiseowl said, plus this would make it consistent throughout
    	// the program (good idea):
    
    	// Notes from dwiseowl:
    
    	
    /* Both string_array and copy_array are the same datatype. No problem with that, 
    but you really do need to understand what that datatype is. 
    
    Let's first concentrate on string_array, since your attempt to use copy_array 
    is completely wrong for what you want to do.
    
    What is string_array's datatype? It is an array of char pointers. 
    
    Do you understand that? Do you understand what that means? That means that each 
    element of the array is a char pointer.
    
    So what is the datatype of string_array[j]? I just told you the answer. 
    
    The answer is that it is a char pointer; it points to a C-style string that 
    resides elsewhere.
    
    Is a char pointer the same thing as a char? 
    
    No, it is not! 
    
    Which is what the compiler keeps telling you when you try to foist a char 
    pointer onto a function (isalpha and tolower) that expects a char.
    
    What you need to do is to access each individual character within each string. 
    Which by a really odd coincidence is what I was talking about when I said, 
    "iterating through the individual characters of each string".
    
    What is a char pointer in C? Isn't it mostly equivalent to a char array? 
    And isn't a char array what a C-style string is? And can't you index into a 
    char array in order to access an individual char? 
    
    Think about that, because that is what you need to do.
    
    Are you familiar with two-dimensional arrays? 
    Are you aware that in C a two-dimensional array is equivalent to an array 
    of arrays? 
    
    So:
    
        string_array is an array of char*, AKA a char**.
        string_array[i] is a char*, which is an array of char.
        Therefore, string_array[i][j] is a single char. QED.
    
    */
    
    	const int array_size = 5;
    
    	// Each element in string_array is a string, or rather a char 
    	// pointer which contains the memory address of the literal strings 
    	// that were created elsewhere
    
    	// These memory addresses are in a read-only part of the RAM
    	// And are pointing to an overarching array.
    
    	char* string_array[array_size] = {"Madam I'm Adam.", "Don't cry for me, Marge and Tina.",
    							  "Lid off a daffodil.", "Red lost soldier.", 
    							  "Cigar? Toss it in a can. It is so tragic."};
    
    	// Declare the copy char* copy_array:
    
    	char* copy_array[array_size];
    
    	// Examine each string with a for loop]
    
    	// Change the conditional to be less than 5 instead of the length
    	// of the entire array
    
    	for(int i = 0; i < array_size; i++)
    	{
    
    		// Output the string
    		// Determine if the string in question aka string_array[i] is a palidrome
    
    		// Maybe I should utilize a function that will literally reverse the 
    		// characters
    
    		// Make an if statement that will test to see if the current element of
    		// string_array is a palindrome
    
    		// I also have to make it rip the punctuation out of the sentence and ignore
    		// spaces
    
    		// I thought maybe to use strcmp() function, but that would just compare
    		// the strings based on alphabetical order
    
    		// strspn(): this function searches a string for the first character that is 
    		// NOT contained in a given set and return the index of the character found
    
    		// Maybe I would make a duplicate array that would copy the phrases from
    		// the string_array and then I should compare the two arrays using the 
    		// strspn() function
    
    		// This would be an okay idea, but I still need to rip out the empty spaces
    		// and format the whole thing to lowercase to remove case-sensitive problems
    		// too
    
    		// Good ideas, continue reviewing string functions on p. 240
    
    		// Let's create a copy of the entire array, that will not contain
    		// periods, commas, or spaces AND make it lower case
    
    		for(int j = 0; j < array_size; j++)
    		{	
    
    			// Make an if statement that will check to see if the current character
    			// is a period, comma, or space, and IF SO, skip to the next element:
    
    			// I've created other literal strings in THE SAME READ-ONLY RAM
    
    			// The following statement will test for quality, and tests the MEMORY 
    			// ADDRESSES of those strings, not the contents of the strings
    
    			// The strings that contain these punctuation marks contain different 
    			// memory addresses than the strings inside the string_array
    
    			// Hence this logic will never succeed
    
    			// What I'm thinking now, is to possibly ditch the idea of 
    			// using pointer to chars, because for whatever reason, I decided
    			// to use them without really understanding that they will point
    			// to memory addresses that contain that value
    
    			// Exactly, why compare memory addresses when I want to look at
    			// SPECIFIC values... Ugh, the logic is so flawed
    
    			// Now that we're checking each STRING inside the string_array
    			// we have to look at individual characters now, so i'm going
    			// to use a for loop with k as its incrementing variable to
    			// really nail the fact that this is a two dimensional array:
    
    			for(int k = 0; k < array_size; j++)
    			{
    				// Double quotes are used for strings 
    				// Single quotes are used for individual characters
    
    				// Make a series of if statements that will look at
    				// spaces, commas, and periods
    
    				// Alright, I think I might have gotten it, let's use the
    				// IsLetter from the Character class in C++/CLI to our 
    				// advantage. That way, whenever an element that is NOT a letter 
    				// aka punctuation is examined, then it will skip to the next
    				// element
    
    				// Old if loop that tried to use IsLetter from the Character
    				// Class in the sense that if the current character of the
    				// string_array being examined WAS NOT A LETTER, then the element
    				// would be skipped:
    
    				// if(!(Char::IsLetter(string_array[j])))
    
    				// Old if loop that checked to see if the current character
    				// was alphabetical, but it only works if we are dealing with
    				// regular character arrays... : 
    				
    				// if (!(isalpha(string_array[j])))
    
    				// 'isalpha' cannot convert the parameter from char* to int...
    
    				// Somehow make it refer to the MEMORY address of the current
    				// character using the & operator:
    
    				// Make an else statement that will catch any known characters
    				// that don't match a space, comma, or period:
    
    			
    				// Store the current character of string_array into the
    				// copy_array:
    
    				// Also, use the tolower() function in order to convert
    				// the current character into a lowercase letter to prevent 
    				// case-sensitive issues
    
    				// Make it refer to the actual memory address, and don't
    				// use logic that is typically used for ordinary character
    				// arrays, since we're dealing with pointers that are hella
    				// hard to figure out
    
    				// We have to use the & address operator to access the particular
    				// MEMORY address, since the location we want to refer to
    				// has a specific memory address
    
    				// Each string within that pointer to character array has its
    				// own location and memory address, and each value that we
    				// want to look at ALSO has its own location and memory address
    
    				// The issue is, how the hell are we going access it using
    				// & operator?
    
    				// Well, *string_array will bring me down to "Madam"
    				// since its one level down, and dereferencing with the
    				// indirectional operator will do this for us
    
    				// **string_array will probably bring us down to TWO levels
    				// aka the first 'M' in madam, so write **string_array:
    
    				// How do I work the left side? 
    
    				// Well, copy_array is much like the string_array, in the sense
    				// that it is an pointer to character array that will
    				// contain 5 separate pointer to character arrays, which have
    				// separate memory addresses and locations, and their values
    				// ALSO have separate memory addresses and locations
    
    				// I would probably have to be on the same level so why not
    				// go down two levels in the copy_array to match the current
    				// character for the string_array.
    
    				// The question also is, how can I use tolower() if it
    				// only takes in an integer value aka an index position
    				// for a NORMAL character array
    
    				// How would I force all of the characters that the
    				// original array, string_array points to, TO lowercase?
    
    				// Also, how am I going to use [j] in this context if 
    				// I can't use any sort of integers in regards to referring to
    				// a particular memory address?
    
    				// First try:
    
    				**copy_array = **string_array;
    
    				// OLD CODE: **copy_array[j] = tolower(**string_array)
    
    			}
    	
    		}
    
    		// Before I move on, I want to fix the errors that are present so at least
    		// I would know that the array was properly copied.
    	}
        return 0;
    }
    Last edited by HauntJemimah; October 21st, 2013 at 02:13 PM.
  20. #11
  21. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    Just quickly since I'm at the end of my lunch break:

    Code:
    		// Let's create a copy of the entire array, that will not contain
    		// periods, commas, or spaces AND make it lower case
    
    		for(int j = 0; j < array_size; j++)
    		{	
    
    			// Make an if statement that will check to see if the current character
    			// is a period, comma, or space, and IF SO, skip to the next element:
    The Talmudic approach (inserting commentary and commentary upon the commentary and commentary upon the commentary of the commentary) is detracting from the readability and is hiding the intent of the code. Commenting should describe what the intent of the code is plus additional information that may be needed by the programmer who's going to have to maintain the code. A balance needs to be found between too few comments and too many.

    I'm assuming that you're still wanting to use that second for-loop to go through each character of a string. Would you have done that with the string, "Madam I'm Adam.", if you only iterate five times? No, you would have only accessed "Madam" and ignored " I'm Adam.". Wouldn't you instead want to iterate for the length of the entire string? string_array[i] is a C-style string. The function that gives you the length of a C-style string is strlen(). Wouldn't you want to use that in the second loop instead of array_size?
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Since I obviously can't understand how to reference pointers, I redid the whole thing without them, though my code is only going through madam only now:
    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    	array<String^>^ phrases = {L"Madam I'm Adam.", 
    							   L"Don't cry for me, Marge and Tina.",
    							   L"Lid off a daffodil.", 
    							   L"Red lost soldier.", 
    							   L"Cigar? Toss it in a can. It is so tragic."};
    
    	String^ letters;
    
    	bool isPalindrome;
    
    	for each(String^ phrase in phrases)
    	{
    
    		// Extract the letters and make them lower case:
    		letters = L"";
    
    		for each(wchar_t ch in phrase)
    			if (Char::IsLetter(ch))
    				letters += Char::ToLower(ch);
    
    	// Test for Palindrome:
    	isPalindrome = true;
    	for (int i = 0; i < letters->Length / 2; i++)
    	{
    		if (letters[i] != letters[letters->Length-i-1])
    		{
    			isPalindrome = false;
    			break;
    		}
    
    	Console::WriteLine(L"\"" + phrase + L"\" " 
    		+ (isPalindrome ? "is":  "is not") + L" a palindrome.");
    
    	}
    		
        return 0;
    }
    
    }
  24. #13
  25. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    Originally Posted by HauntJemimah
    So after reading the article, I learned a lot though, the explanation on the very last example had my mind reeling (everything else was pretty straight forward up to that point but I tried)

    Anyway, so I'm trying to put the same example inside Visual Studio 2008 in a C++/CLI console program, but am having trouble with the array syntax.

    I know the last array is a pointer to char array but I'm not sure about the over arching arrays. Do we assume that they are just arrays that contain arrays and the only pointer to char array is the final array, ap[]?

    Anyway, here's my code thus far, pretty much what the author has, and I'll add my **** ton of extra notes later but I didn't include them as to not make too much clutter.

    The main problem is with the use of brackets I believe, please help.

    Here's my code:

    Code:
    // Chapter4_PointerPower.cpp : main project file.
    
    #include "stdafx.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    	// Create the pointer to char array that the author has:
    	*char pppp[ppp [app[ap["INTEGER", "PROPORTION", "DEBUGGER", "PORTABLE", "TOWER"]]]]
    
    	// First example in the article:
    	printf("%.*s", 2, *--**pppp);
    
    	// Second example in the article: 
    	printf("%.*s", 3, *(++*pppp[0] - 4)); 
    
    	// Third Example (incomplete... the author didn't include a printf statement 
    	// before it)
    	printf("%.*s",(++*--*++pppp[0] + 5))
    
    	// Fourth Example:
    	printf("%.*s", 2, *++pppp[0][3] + 3); 
    
    	// Fifth Example:
    	printf("%s\n", (*pppp + 2)[-2][2] + 2);
    
    
        return 0;
    }
    I'm basing it off the diagram that was in the article:

    http://collaboration.cmc.ec.gc.ca/science/rpn/biblio/ddj/Website/articles/CUJ/1993/9303/skelly/fig1.htm
    I don't normally quote an entire message like that, but I felt it necessary to retain context. Also, I didn't get around to this until now since this is the first spare time I had to sit down and look at it.

    At work we've used Visual C++ v1.52 (to support older products using a 16-bit processor) and v6 for GUI utilities. It was a few years ago that I got on a project that used VS 2008, though other programmers here had been working with it for a while already. When I got a Win7 (64-bit) desktop for at home I discovered that it refused to allow me to install VC++6, so I downloaded Visual C++ 2008 Express. I started to try to play with Windows Forms and soon discovered that Microsoft had radically changed C++ in order to shoehorn it into a .NET environment; just the evolution of figuring out how to convert between basic string objects and .NET Strings would have had me tearing my hair out if I didn't maintain a GI haircut. Having to learn C++/CLI was like having to learn a different language, one which conflicted with playing with the new 1998 standard, so I decided that I should instead give up on C++/CLI and just plain learn another language. That's why I chose to learn C# instead (though I've been side-tracked from that for over a year now).

    To be honest, I have no idea what all those brackets are about in that array "declaration" (or whatever it is) --
    *char pppp[ppp [app[ap["INTEGER", "PROPORTION", "DEBUGGER", "PORTABLE", "TOWER"]]]]
    Besides, that departs from the author's exercise.

    I'll need to wait a few days to have time to intensively step through that exercise. Is part of the problem that you aren't considering the order of precedence (Key Fact #11)? That will determine the order of evaluation.

    For example, there's a standard implementation of strcpy using pointers:
    Code:
    char *StrCpy(char *dest, const char *src)
    {
        // declare working pointers and initialize to the parameters
        char *sp = src,
               *dp = dest;
    
        // loop until you hit the null-terminator in src
        // copy the character in sp to dp and then increment both
        //     to the next character position.
        while (*sp)
            *dp++ = *sp++;
    
        // null-terminate dest and return dest
        *dp = '\0';
        return dest;
    }
    What makes the assignment statement in the loop work is that ++ has a higher precedence than dereferencing does, so it's the pointer that's getting post-incremented and not its contents. If you wanted to increment the value that a pointer is pointing to, then you'd have to use parentheses to override precedence: (*dp)++

    Just glancing at the author's explanation of the expressions, that's what I see him doing. He starts with the pointer, pppp, and uses the order of precedence to show what operation binds the closest to it, and then from that point on what operation binds closest to the previous operation.
  26. #14
  27. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,154
    Rep Power
    2222
    Originally Posted by HauntJemimah
    I redid the whole thing without them, though my code is only going through madam only now:
    Your indentation is off, which is hiding the bug from you. Here is your code properly indented -- the bug is towards the bottom:
    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    	array<String^>^ phrases = {L"Madam I'm Adam.", 
    							   L"Don't cry for me, Marge and Tina.",
    							   L"Lid off a daffodil.", 
    							   L"Red lost soldier.", 
    							   L"Cigar? Toss it in a can. It is so tragic."};
    
    	String^ letters;
    
    	bool isPalindrome;
    
    	for each(String^ phrase in phrases)
    	{
    
    		// Extract the letters and make them lower case:
    		letters = L"";
    
    		for each(wchar_t ch in phrase)
    			if (Char::IsLetter(ch))
    				letters += Char::ToLower(ch);
    
    		// Test for Palindrome:
    		isPalindrome = true;
    		for (int i = 0; i < letters->Length / 2; i++)
    		{
    			if (letters[i] != letters[letters->Length-i-1])
    			{
    				isPalindrome = false;
    				break;
    			}
    
    			Console::WriteLine(L"\"" + phrase + L"\" " 
    				+ (isPalindrome ? "is":  "is not") + L" a palindrome.");
    
    		}
    		
    		// Why did you place the return inside the for-loop?
    		// This causes you to terminate the program after only one 
    		//    iteration, which is causing the bug.
    		return 0;
    	}
    
    	// This is where the return 0 should go instead.
    }
    Don't give up on learning pointers. They are an absolutely vital part of C and of C++.

    Of course, they are not allowed in C# nor in Java and I have no idea of their role in C++/CLI, since pointers seem to be counter to the idea of managed code. In C# and Java, their role is assumed by references, which is basically the same thing as pointers only without the syntax.
    Last edited by dwise1_aol; October 22nd, 2013 at 02:40 PM.
  28. #15
  29. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2013
    Posts
    232
    Rep Power
    2
    Originally Posted by dwise1_aol
    Your indentation is off, which is hiding the bug from you. Here is your code properly indented -- the bug is towards the bottom:
    Code:
    // Chapt4_Exercise6.cpp : main project file.
    
    #include "stdafx.h"
    #include "ctype.h"
    
    using namespace System;
    
    int main(array<System::String ^> ^args)
    {
    
    /* Write a C++/CLI program that creates an array containing the following strings:
    
    “Madam I’m Adam.”
    “Don’t cry for me, Marge and Tina.”
    “Lid off a daffodil.”
    “Red lost soldier.”
    “Cigar? Toss it in a can. It is so tragic.”
    
    The program should examine each string in turn, output the string and indicate 
    whether it is or is not a palindrome (that is, the same sequence of letters reading 
    backward or forward, ignoring spaces and punctuation).
    
    */
    
    	array<String^>^ phrases = {L"Madam I'm Adam.", 
    							   L"Don't cry for me, Marge and Tina.",
    							   L"Lid off a daffodil.", 
    							   L"Red lost soldier.", 
    							   L"Cigar? Toss it in a can. It is so tragic."};
    
    	String^ letters;
    
    	bool isPalindrome;
    
    	for each(String^ phrase in phrases)
    	{
    
    		// Extract the letters and make them lower case:
    		letters = L"";
    
    		for each(wchar_t ch in phrase)
    			if (Char::IsLetter(ch))
    				letters += Char::ToLower(ch);
    
    		// Test for Palindrome:
    		isPalindrome = true;
    		for (int i = 0; i < letters->Length / 2; i++)
    		{
    			if (letters[i] != letters[letters->Length-i-1])
    			{
    				isPalindrome = false;
    				break;
    			}
    
    			Console::WriteLine(L"\"" + phrase + L"\" " 
    				+ (isPalindrome ? "is":  "is not") + L" a palindrome.");
    
    		}
    		
    		// Why did you place the return inside the for-loop?
    		// This causes you to terminate the program after only one 
    		//    iteration, which is causing the bug.
    		return 0;
    	}
    
    	// This is where the return 0 should go instead.
    }
    Don't give up on learning pointers. They are an absolutely vital part of C and of C++.

    Of course, they are not allowed in C# nor in Java and I have no idea of their role in C++/CLI, since pointers seem to be counter to the idea of managed code. In C# and Java, their role is assumed by references, which is basically the same thing as pointers only without the syntax.
    *Jaw drop + ("ARE YOU ****ING KIDDING ME!?!?!?! I MISSED THAT?! --> At myself)


    Anyway. Good point, I totally get it after reading that article and its an awesome reference.

    That was worth more the book I got on my comp alone (though... let's say I'm a pirate heh ;D)

    Just glancing at the author's explanation of the expressions, that's what I see him doing. He starts with the pointer, pppp, and uses the order of precedence to show what operation binds the closest to it, and then from that point on what operation binds closest to the previous operation.
    Yup, that I totally understood and his approach on how to break down Pointer arithmetic in terms of operator precedence was amazing, and actually really straightforward after I sat down with it for 2 days taking notes on each bit in a Wordpad doc (like any other topic I learn, or I take notes in code for every example).

    But yeah, I don't want to ditch them, but its hilarious because I realized a for each loop just as a previous user had mentioned would have done a better job.

    I remember .NET being mentioned in the book and it probably states specifically in the beginning how it was being implemented, but I didn't know that MS had a sudden inclination to use it as opposed to previous versions, interesting.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo