-1

I just want you to ask what did I do wrong with this code. I wrote a function that take a char* in parameter, I want to modify it directly without returning smthg, and reverse the string.

#include <iostream>

void reverseString(char *p_string){

    int length = strlen(p_string);
    int r_it = length - 1;
    char* tmp = (char*)malloc(length);
    int last_it = 0;

    for (int i = 0; i != length; i++){
        tmp[i] = p_string[r_it];
        r_it--;
        last_it++;
    }
    tmp[last_it] = '\0';

    strcpy_s(p_string, length + 1, tmp);
    //free(tmp);
}

int main(){

    char str[] = "StackOverflow";

    reverseString(str);

    std::cout << str << std::endl;

    system("pause");
}

I'm used to C++ and don't often use C functions like malloc/free/strcpy... Here, my problem is, when I alloc memory for my temporary char, I called mallec(length) for length = 13 in this case, char = 1 bytes so it should be allocate memory for 13 char is that right?

Problem is allocate more space than need so i need to use '\0' before my strcpy_s if not it breaks.

Did I do a mistake somewhere? Also, when i call free(tmp), it breaks too and say heap corruption, but I didn't free the memory before that.

Thanks for helping !

Rahul Nikate
  • 6,192
  • 5
  • 42
  • 54
Jack
  • 13
  • 1
  • 4
  • 4
    so do malloc (length + 1) – pm100 Nov 20 '14 at 17:32
  • The title of your question is extremely vague. Please change it to something more descriptive. – dandan78 Nov 20 '14 at 17:33
  • That you're even allocating memory at all for this task is root-problem-one. – WhozCraig Nov 20 '14 at 17:35
  • Why? if i do mallonc(length) with length = 13, the char tmp is 32 long... – Jack Nov 20 '14 at 17:35
  • If you allocate 13 bytes, how can it be 32 long? – P.P Nov 20 '14 at 17:36
  • That's why i ask... with this : std::cout << strlen(p_string) << std::endl; std::cout << strlen(tmp) << std::endl; I correctly have 13 for p_string length but 32 for tmp... – Jack Nov 20 '14 at 17:37
  • 1
    `strlen(tmp)` producing `32` does **not** mean you have allocated 32 bytes. It means you haven't properly NUL-terminated your string. – nobody Nov 20 '14 at 17:40
  • 1
    pm100 is correct, you need to allocate length + 1. When you do not, the line "temp[last_it]='\0'" is going to overwrite heap memory which follows your string, because you did not allocate enough space to include the '\0'. – Chris Nov 20 '14 at 17:40
  • I'm confused as to why you're messing with C-style memory allocation at all. If you're assigned the task of reversing a C-style string and are constricted to not use standard library functions like [`std::reverse`](http://en.cppreference.com/w/cpp/algorithm/reverse) (the truly correct approach), a C-solution is easily doable in-place with no memory allocation requirements *at all* : [**see it live**](http://ideone.com/ydHq4N). – WhozCraig Nov 20 '14 at 17:45
  • @WhozCraig I mess with it because it was a test i had in a interview for a job. The code i wrote in my first post is working correctly... i do not have a heap corruption when i had \0, but when i free the memory But the function do his job – Jack Nov 20 '14 at 17:47
  • @Jack it could work but it depends on your system. Note that it did not on my system... That's the issue with memory corruption, you can not predict how it will impact your system. On one system nothing appears to happen, on others it overwrites something critical and pop. Anyhow, good luck on the job. – Chris Nov 20 '14 at 18:07

4 Answers4

2

I took your original code and added a simple '+1' to the size of the malloc and got a passing result.

Not sure if your exercise is related specifically to the use of malloc, but have you considered doing the reversal directly inside the original string?

For example:

void reverseString(char *p_string){

    char* p_end = p_string+strlen(p_string)-1;
    char t;

    while (p_end > p_string)
    {
        t = *p_end;
        *p_end-- = *p_string;
        *p_string++ = t;
    }
}

int main(){

    char str[] = "StackOverflow";

    reverseString(str);

    std::cout << str << std::endl;

    system("pause");
}

If you are required to use malloc, then you need to ensure that you allocate enough space for string which includes the '\0'

Chris
  • 2,655
  • 2
  • 18
  • 22
1

You must use

int length = strlen(p_string);
int r_it = length - 1;
char* tmp = (char*)malloc(length+1);

Since strlen doesn't count the \0 character. So this will fail if you don't use length+1:

tmp[last_it] = '\0';

The length of a C string is determined by the terminating null-character: A C string is as long as the number of characters between the beginning of the string and the terminating null character (without including the terminating null character itself). http://www.cplusplus.com/reference/cstring/strlen/

Btw. C99 support semi dynamic arrays. So could you try this:

char tmp[length+1];

Source: http://en.wikipedia.org/wiki/Variable-length_array

float read_and_process(int n)
{
    float vals[n];

    for (int i = 0; i < n; i++)
        vals[i] = read_val();
    return process(vals, n);
}
stupidstudent
  • 678
  • 4
  • 13
  • Something is still wrong. I tried: malloc(sizeof(char)), tmp's length is now 16... And if i do a dynamic arrays visual studio is still demanding a const value :/ – Jack Nov 20 '14 at 17:43
  • This is because you are using a C++ compiler. "Not part of standard C++ (in C99 and as a compiler extension for gcc)." http://stackoverflow.com/questions/2672085/c-static-array-vs-dynamic-array This malloc(sizeof(char)) = malloc(1). Size Of does not return the size of an array in C. An array is just a Pointer. sizeof(char*) returns the number of bytes, a pointer on your system has (32 or 64 most likely). – stupidstudent Nov 20 '14 at 17:46
  • I tought a char = 1 bytes no matter what – Jack Nov 20 '14 at 17:53
  • Yes, but an Array of chars is something different than an char. sizeof(char) = 1, sizeof(char*) = 4 or 8 (32 or 64 bits). Very important: if you string doesn't end with \0, strlen will search the whole memory of your pc until it finds \0 (or the OS says: stop and kill). strlen counts the number of bytes between the start of an array (lets say 1024) and the first occurence of a \0. So stack overflow is: Stackoverflow\0 1024+12+1 (\0) = 1037. strlen will calcuclate: 1036 (where \0 is -1) - 1024 (the address str[]) = 12. If Stackoverflow doesnt have a \0 (C appends it automaticly) it continues. – stupidstudent Nov 20 '14 at 17:56
  • "Something is still wrong. I tried: malloc(sizeof(char)), tmp's length is now 16..." you said to the OS: give me 1 Byte and a pointer named tmo to it. When you strlen(tmp) with out setting it \0, it will go on until it finds somewhere in memory \0. This isn't good. strcpy_s(p_string, length + 1, tmp); would C overwrite the tmp size I think it is Microsoft Stuff. http://msdn.microsoft.com/de-de/library/td1esda9.aspx... Not sure if more than 1 character is copied than it tries to find \0 or it will just copy 1 char. MS can use a template version. MS code, not C standard. Can't say more about it. – stupidstudent Nov 20 '14 at 18:05
0

Check the below C code: The memory allocated to tmp should be length+1 as done below and also there are many unnecessary variables which can be avoided.

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void reverseString(char *p_string){

   int i;
   int length = strlen(p_string);
   int r_it = length - 1;
   char* tmp = (char*)malloc(length+1);

   for (i = 0; i != length; i++){
      tmp[i] = p_string[r_it--];
   }   
   tmp[i] = '\0';

   strcpy(p_string, tmp);
   return;

}

int main(){

   char str[] = "StackOverflow";

   reverseString(str);

   printf("%s",str);
   return 0;

}
Gopi
  • 19,784
  • 4
  • 24
  • 36
0

There is nothing fundamentally wrong with your approach, just some of the details. Since I am not sure how you found out that the sizeof(tmp) is 32, I modified your code to the one below which includes a few printfs and some minor changes:

#include "stdio.h"
#include "stdlib.h"
#include "string.h"

void reverseString(char *p_string)
{
  size_t length = strlen(p_string);
  size_t r_it = length - 1;
  char* tmp = (char*)malloc(length+1);
  int last_it = 0;
  size_t i=0;

  printf("strlen(p_string) = %d\n", strlen(p_string));
  printf("Before: strlen(tmp) = %d\n", strlen(tmp));

  for (i = 0; i != length; i++) {
    tmp[i] = p_string[r_it];
    r_it--;
    last_it++;
  }

  tmp[last_it] = '\0';

  printf("After: strlen(tmp) = %d\n", strlen(tmp));

  strcpy(p_string, tmp);

  free(tmp);
}

int main()
{
  char str[] = "StackOverflow";

  reverseString(str);

  printf("%s\n", str);

  return 0;
}

First, I have removed all C++ specific code - you can now compile this with gcc. Running this code yields this output:

sizeof(p_string) = 13
Before: strlen(tmp) = 0
After: strlen(tmp) = 13
wolfrevOkcatS

This is to be expected - strlen basically counts bytes until it hits the \0 character and so the first time we print the size using strlen, it returns 0 since we just allocated the memory. As another poster suggested, we have to allocate 1 extra byte to store the \0 in our new string.

Once the reverse is complete, 13 bytes would have been copied over to this memory and the second strlen returns the expected answer.

vikramls
  • 1,802
  • 1
  • 11
  • 15