C sizeof problem

Started by
43 comments, last by _the_phantom_ 15 years, 9 months ago
I had an interview today for a possible internship with a company supplying IPTV solutions. The interviewer asked a technical question, which I got with a little bit of help here and there but he said it was just as important to communicate how to solve the problem as well as actually implementing it. No idea whether I got the job, but we'll see. The question he asked was write a C function to reverse a string. So I came up with something on a whiteboard which he seemed relatively happy with. I wanted to be sure I could always do it so I tested the code again at home, at which point I hit a weird issue (as I usually do when working with C, I might add). Here's the code I wrote ('scuse the messiness of it, I was just hacking about):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void strRev(char* originalString);

int main()
{

	char* source;

	source = "hello";

	strRev(source);

	return (0);
}


void strRev(char* originalString)
{	
	char* tempString = NULL;
	int i = 0;
	int j = 0;
	int lengthOfTempString = 0;
	int lengthOfOriginalString = 0;
	
	lengthOfOriginalString = strlen(originalString);

	tempString = malloc(sizeof(char) * lengthOfOriginalString);

	lengthOfTempString = strlen(tempString);

	printf("Length of tempString: %i\n",lengthOfTempString);
	printf("Length of originalString: %i\n",lengthOfOriginalString);
	
	printf("sizeof(char): %i\n",sizeof(char));
	
	for (i = strlen(originalString); i >= 0; i--)
	{
		if (originalString == '\0')
		{
			printf("Null terminator detected\n");
		}
		else
		{
			tempString [j] = originalString;
			j++;
		}
	}
	

	*tempString+='\0';

	printf("Original string: %s",originalString);
	printf("\n");
	printf("Newly reversed string: %s",tempString);
		
	free(tempString);
}


Now, when I run this, I see something interesting. The strlen of originalString is 5, as it should be, and this is what the code reports. So why is the strlen for tempString 9? That doesn't make any real sense to me, where's the 9 coming from? I know the size of a char* pointer is 4 bytes but that isn't important or relevant here from what I can see, even still there's no way that you could get 9 out of that. When it prints out tempString, I see the right output followed by 4 extra bytes of utter crap because the buffer is too big. I'm now getting 9, which is an improvement on the even more random 16 and 24 I was getting earlier. Similarly, when I do:

tempString = malloc(sizeof(char));
without the additional sizeof as shown above, the length of tempString is apparently 16?? I really don't get what's going on here, I'm not exactly Brian Kernaghan when it comes to C but that just seems plain wrong. How does having a char*, then assigning it dynamically to a standard char produce 16? Shouldn't it be 1, or 4? I'm compiling using VS2005 if that helps, maybe something weird about the compiler? This is actually bugging me, it doesn't seem right. Where did I go wrong? TIA, ukd.
Advertisement
strlen works by reading memory at a pointer until it finds a null-terminator. malloc just allocates data, it does not initialize it. The solution to your problem is to initialize your buffer.

	tempString = malloc(sizeof(char) * lengthOfOriginalString);	memset(tempString, 0, sizeof(char) * lengthOfOriginalString);	lengthOfTempString = strlen(tempString); // = 0
	lengthOfOriginalString = strlen(originalString);	tempString = malloc(sizeof(char) * lengthOfOriginalString);	lengthOfTempString = strlen(tempString); /* UH-OH! */	printf("Length of tempString: %i\n",lengthOfTempString);	printf("Length of originalString: %i\n",lengthOfOriginalString);

See the line marked with the "UH-OH" comment? Since we know that strlen works by seeking sequentially through the character array for null termination, but we just allocated the memory and have no idea what's in it... where's the null? 1 character away? 9? 16? 1015?

Yeah, exactly.
You didnt initialize your buffer. Use calloc for your allocation, or malloc it then memset it. I prefer calloc, because thats what its for.

lengthOfOriginalString = strlen(originalString);tempString = calloc(sizeof(char) * lengthOfOriginalString + 1, 1);lengthOfTempString = strlen(tempString);

You should still however expect the value of lengthOfTempString to be zero, because you haven't put a string into it yet.

[edit]

Damnit, why do I have to be such a slow typist!?

[edit, again]

You also forgot to add 1 byte for the null terminator.
The C standard defines sizeof(char) as 1. I think your problem here is that there isn’t a '\0' at the end of the string when you calculates its length. strlen calculates the numbers of chars before the first '\0' in memory.

It’s possible to reverse a string without using additional space (I haven’t tested it):
void strRev(char *str){    size_t len = strlen(str);    size_t n;    for (n = 0; n < len/2; ++n) {        char tmp = str[n];        str[n] = str[len - n - 1];        str[len - n - 1] = tmp;    }}


Edit: Too slow... [bawling] [lol]
Edit 2: I thought your objective was to modify the string passed reversing it. But your code don’t do that.
Quote:Original post by apatriarca
The C standard defines sizeof(char) as 1. I think your problem here is that there isn’t a '\0' at the end of the string when you calculates is length. strlen calculates the numbers of chars before the first '\0' in memory.

It’s possible to reverse a string without using additional space (I haven’t tested it):
*** Source Snippet Removed ***

Edit: Too slow... [bawling] [lol]


This would be a good place to use XOR swap. Some interviewers seem to love this kind of bullshit: [grin]

void strRev(char *str){    size_t len = strlen(str);    size_t n;    for (n = 0; n < len/2; ++n) {        str[n] ^= str[len - n - 1];        str[len - n - 1] ^=  str[n];        str[n] ^= str[len - n - 1];    }}
Quote:Original post by fpsgamer
This would be a good place to use XOR swap. Some interviewers seem to love this kind of bullshit: [grin]

I never understand why the XOR swap is supposed to be faster than the simpler and easier to read and understand one (not considering my favorite swap: std::swap). I have tested the two versions on my machine once and the XOR swap was slower. But I doubt is worth optimizing things like that.
Quote:Original post by apatriarca
Quote:Original post by fpsgamer
This would be a good place to use XOR swap. Some interviewers seem to love this kind of bullshit: [grin]

I never understand why the XOR swap is supposed to be faster than the simpler and easier to read and understand one (not considering my favorite swap: std::swap). I have tested the two versions on my machine once and the XOR swap was slower. But I doubt is worth optimizing things like that.


They prefer it because the interview would end too quickly if you could just use std::reverse like a sane developer :)
I was actually told another way to do it by pointing to the start and end of the string, swapping the values until you reach the middle of the string. Might try that one next.

calloc solved the problem, thanks for your help! It's now screamingly obvious that I didn't initialise the buffer, I didn't think of zeroing it for some reason :S

It all seems so clear now, thanks for your help.
Quote:Original post by ukdeveloper
I was actually told another way to do it by pointing to the start and end of the string, swapping the values until you reach the middle of the string. Might try that one next.

It’s exactly the method I have implemented earlier. It use array indices instead of pointers but the logic is the same.

Quote:
calloc solved the problem, thanks for your help! It's now screamingly obvious that I didn't initialise the buffer, I didn't think of zeroing it for some reason :S

calloc initialize the entire buffer even if you only need to set the last char of the string to '\0'. A simple tempString[lengthOfOriginalString] = '\0' is enough.

Quote:
They prefer it because the interview would end too quickly if you could just use std::reverse like a sane developer :)

:) This is also the reason they have asked for a C implementation. In C++ it would have been too easy.

This topic is closed to new replies.

Advertisement