1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

Common mistakes and errors

From cpwiki

Jump to: navigation, search

Contents

Using pointers without allocating them

Pointers are variables that store a memory address, only. They do not actually have any space for storing a string. In the world of C and C++, we must ask for storage to get it. Once we have a storage somewhere, it is safe to point a pointer at that memory location. By default, what memory address a pointer is assigned when created is undefined, and can point to anywhere. This is usually somewhere where the program does not have a storage, thus leading to undefined behavior:

char* mystr;
char* mystr2 = "My string";
strcpy(mystr, mystr2);

Allocating (asking for storage) can be done in two ways. Either by the stack:

char mystr[100];
char* pMyStr = mystr; /* Set pointer to the new storage */
strcpy(pMyStr, "My string"); /* OK */
/* free(pMyStr); -- DO NOT FREE! */

This creates a storage for a string that can store up to 99 characters + a null character. Or by the heap:

char* pMyStr = malloc(100);
strcpy(pMyStr, "My string"); /* OK */
free(pMyStr);
pMyStr = NULL;

In C++, new/delete should be used instead of malloc/free. Also see string literals should be const.

String literals should be const char

A string literal is typically stored in read-only area, thus they cannot be modified. However, both C and C++ allows string literals to be stored inside a pointer to char (not pointer to const char), which is a pitfall because trying to modify the string would result in an access violation. The correct way is to store a string literal in a pointer to const char, which would cause a compile error if the string was about to be modified. Wrong way:

char* str = "This is my string";
str[5] = 'n';

Compiles fine, but does not always execute well, because the memory used for the string is "read only", so it can't be written to. A way to make the compiler prevent this:

const char* str = "This is my string";
str[5] = 'n';

Will not compile because str is const. Compiler will catch the error for you. For more information, see Virtual Memory. The way to achieve the correct behaviour when changing a string from the code:

char str[] = "This is my string";
str[5] = 'n';

This way, we have preserved some space for the string that can be written to, that is initialized to a string of "This is my string". This works ok as long as we don't need to extend the string.

Extending string constants without creating enough space

A string template is created, and then other strings added to the string to extend it, without first creating space for that extra data, e.g:

char ext[] = ".txt";
char name[] = "myfile";
	
strcat(name, ext);

This will overwrite whatever happens to be behind the variable. name.

Instead, make sure there is enough space to extend the string: +

char ext[] = ".txt";
char name[16] = "myfile";

strcat(name, ext);

This way, there's enough space (and some extra in this case) to append the extension to the original string.

Also see Buffer overrun.


Difference in levels of indirection

Don't use the address of operator when passing an array to a function that expects a pointer. The reason is that when passing an array, the address to its first element is passed, thus creating a pointer. If using the address of operator, we will get a pointer to the array, which is a different type, and also behaves differently than a raw pointer.

Example:

void foo(char* MyStr) { }
int main()
{
    char MyStr[] = "Hello World!";
    /* This is wrong! */
    foo(&MyStr); /* Passing MyStr as char(*)[13] */
    // This is right!
    foo(MyStr); /* Passing MyStr as char* */
}

The first would give a warning in C and an error in C++.

For more information, see A pointer on pointers.

Avoiding problems with printf and scanf

At our board there are at times many questions posited by newbies, who confuse printf and scanf's arguments.

Scanf's job is to convert text input to a data of some type, according to the format string. The format string is the first argument that should be passed to scanf. When passing other arguments to scanf, all the variables passed to write data to must be passed as pointers, so scanf can write to specific memory locations easily.

Scanf is a function that, by default, reads from the keyboard. Here is an example use of scanf with several data types.

    double g;
    float f;
    char str[32];
    char c;
    int d;

    scanf( "%f %d %c %30s %f", &g, &d, &c, str, &f );


One of the first things to notice is that we use the address-of operator (&) to pass the address of arithmetic and integer types. Strings are converted to a pointer to the first element in this context so there is no need to use &.
Another thing to notice is that a suitable size is used along with %s to avoid overflow. This is a very easy to ignore security concern that can be the source of underhanded, hard to detect bugs. For more information, see scanf woes.

printf is essentially the same, but works in reverse. Its arguments are converted to text and written to the screen, or a file. The example again:

    printf( "%g %s %d %c %f\n", g, str, d, c, f );

Simply pass your format string and variables to printf. Prevent clever exploits by always supplying a format string.

Personal tools