Click to See Complete Forum and Search --> : Help me translate this to C


Gnu/Vince
09-17-2001, 01:23 PM
Here's a simple Ruby example of string use. Please help me put that in C.


#!/usr/bin/ruby

# Define two strings
string1="Hello"
string2="World"

# Concatenate the strings into a bigger variable
wholestring=string1 + " " + string2

# Print the big string
puts wholestring


Please help me, I often use strings in my programs and I can't use C because of this lack.

TheLinuxDuck
09-17-2001, 01:58 PM
#include <stdio.h>
#include <string.h>

int main(void)
{
// All variables in C must be declared before
// use. This allows the programmer to know
// at all times what variables exist, and
// what don't. Plus, they must be declared
// at the beginning of a block of code.
//
// A string is actually an array of chars. This
// first declaration is also a definition.
// We must let C know how much space we will
// be using for each string at all times. This
// is because C doesn't do the memory management
// for you, as ruby does.
//
// We are assigning a maximum of 10 chars
// for this string.
//
char string1[10]="Hello";
char string2[10], wholestring[20];
//
// a temp variable used to make sure we don't
// go over our maximum amount of chars allocated.
//
int whStrLen;
//
// I used the above declaration/definition and
// the following method to show two different
// ways to assign a string. I use this method
// more than the above method.
//
// strncpy copies one string to another, but
// only allowing for n characters to be copied.
// This makes sure that a buffer overrun is
// not done. (overwriting memory that has not
// been allocated, this usually causes a core
// dump).
//
strncpy(string2,"world!",10);
//
// We copy the first string onto the second
// string. Since wholestring is only 20
// characters, we tell it to disallow anything
// over 20 chars.
//
strncpy(wholestring,string1,20);
//
// Since we're going to append more data onto
// the end of the string, we need to make
// sure that we don't do past our allocated
// memory space. We know that wholestring only holds
// 20 chars, so we get how many chars are already
// in it, and then subtract that from 20.
// strncat concatenates one string onto another, stopping at n characters.
//
whStrLen=strlen(wholestring);
strncat(wholestring," ",20-whStrLen);
//
// Same thing
//
whStrLen=strlen(wholestring);
strncat(wholestring,string2,20-whStrLen);
printf("String: %s\n",wholestring);
//
// Snprintf works just like the printf
// equivalent, but puts the resultant string
// into another string, making sure that the
// new string does not exceed n chars. (I've
// made this one reverse the two string, so that
// you can see what it did).
//
snprintf(wholestring,20,"%s %s",string2,string1);
//
// Show our results
//
printf("String: %s\n",wholestring);
return 0;
}


Hope that helps!

[ 17 September 2001: Message edited by: TheLinuxDuck ]

Gnu/Vince
09-17-2001, 02:50 PM
Originally posted by TheLinuxDuck:
<STRONG>
Hope that helps!</STRONG>

Comments would be good.

TheLinuxDuck
09-17-2001, 04:04 PM
Sorry!!! I made an assumption as to the extend of your knowledge of C. (^=

I've modified the source code to include comments.. if I haven't touched on a specific item enough, please ask.

Also, there are easier ways to do this, but you'll be opening yourself up for lots of trouble down the road. It's better to learn this the harder way and to make sure that your code is as secure as it can be.

MrNewbie
09-17-2001, 04:21 PM
C++ will be an easier language to do that because of the string class.

pinoy
09-17-2001, 05:42 PM
#include &lt;stdio.h&gt;

int main(void)
{
char *string1 = "Hello";
char *string2 = "World";
char wholestring[256];

sprintf(wholestring, "%s %s", string1, string2);
puts(wholestring);
return 0;
}


It's pretty much the same as your code except for sprintf.

element-x
09-17-2001, 07:02 PM
TheLinuxDuck, I do believe you left some extra room for an entire book there :D though I suppose for a novice programmer that type of commenting would be extraordinary(sp?).

Good job! :D

Strike
09-17-2001, 07:15 PM
Here's a C++ version:


#include &lt;iostream&gt;
#include &lt;string&gt;

using namespace std;

int main() {
string string1 = "Hello";
string string2 = "World";

string wholestring = string1 + " " + string2;

cout &lt;&lt; wholestring &lt;&lt; endl;
}


[ 17 September 2001: Message edited by: Strike ]

jemfinch
09-18-2001, 10:12 AM
It's not C convention to allocate memory in a function, since then there's the question of who should free to memory. So the standard way for C functions that operate on strings work is to take a char * buffer as an argument, and put the stuff in there, letting the function caller allocate the buffer himself. Another interface question in C is whether to return null-terminated strings (the standard way of representing strings in C -- the only problem is that it doesn't work for binary data) or not. I prefer not using null terminated strings, because they're generally just a bad idea. So here's a general purpose function that should do what you want:


int copy_string(char *buf, char *s, int len_s, char *t, int len_t) {
int i;
for(i=0; i &lt; len_s; i++) *buf++ = *s++;
*buf++ = ' ';
for(i=0; i &lt; len_t; i++) *buf++ = *t++;
return 0;
}


If you want to allocate the string yourself, try this:


char * copy_string(char *s, int len_s, char *t, int len_t) {
int i;
char *buf;
buf = malloc(len_s+len_t+1);
if(!buf) return NULL;
for(i=0; i &lt; len_s; i++) *buf++ = *s++;
*buf++ = ' ';
for(i=0; i &lt; len_t; i++) *buf++ = *t++;
return buf;
}


C really isn't the language for string modification. "I can't use C because of this lack" is really no different from what I say, "I won't use C because of this lack" -- C isn't made for string modification, and it's just much more painful in C than it is in other languages.

(as a note, ocaml does work with strings both very quickly and very easily.)

Jeremy

pinoy
09-18-2001, 05:40 PM
It's not C convention to allocate memory in a function, since then there's the question of who should free to memory.

Actually this is how strdup does things. But you're probably right, it's not the usual way of doing things.

Here's another version of the same code.

char *copy_string(char *s, char *t)
{
char *buf = NULL;
char *p = NULL;

buf = malloc(strlen(s) + strlen(t) + 2);
if (!buf) return buf;

p = buf;
while (*s) *p++ = *s++;
*p++ = ' ';
while (*t) *p++ = *s++;
*p = 0;
return p;
}


Note the +2 in the malloc for the extra ' ' and the null terminator.

C isn't such a bad language. It is unfortunately difficult to do string manipulation in C, because it is very related to pointer manipulation and memory management. On the other hand, it isn't until you've mastered pointer manipulation and memory management that you start to appreciate the power of C.

Gnu/Vince
09-19-2001, 05:21 PM
Originally posted by pinoy:
<STRONG>
#include &lt;stdio.h&gt;

int main(void)
{
char *string1 = "Hello";
char *string2 = "World";
char wholestring[256];

sprintf(wholestring, "%s %s", string1, string2);
puts(wholestring);
return 0;
}


It's pretty much the same as your code except for sprintf.</STRONG>

Wouldn't that make a buffer overrun possible?

pinoy
09-19-2001, 05:47 PM
Wouldn't that make a buffer overrun possible?


No. I know exactly how big the strings are "Hello" + ' ' + "World". char wholestring[256]; is actually too much. You would use snprintf if you have no total control of the inputs.

Gnu/Vince
09-19-2001, 06:40 PM
OK. And how about adding actual user input?


#!/usr/bin/ruby

# Ask for string1 and string2
print "Enter string1: "
string1=STDIN.gets.chomp!
print "Enter string2: "
string2=STDIN.gets.chomp!
# Do the concatenation
wholestring=string1+string2
# Display the string
puts wholestring

debiandude
09-19-2001, 06:53 PM
This should do it.

char string1[80];
char string2[80];
char *concat;

fprintf(stderr, "Enter: ");
fgets(string1, sizeof(string1), stdin);
fprintf(stderr, "Enter: ");
fgets(string2, sizeof(string2), stdin);

concat = (char *)malloc(strlen(string1)+strlen(string2)+2);

sprintf(concat, "%s %s", string1, string2);

fprintf(stderr, "%s", concat);


[ 19 September 2001: Message edited by: debiandude ]

[ 19 September 2001: Message edited by: debiandude ]

pinoy
09-19-2001, 07:17 PM
sprintf(concat, "%*s", sizeof(concat)-1, "%s %s", string1, string2);


??? This doesn't work. First the format string is only evaluated once. This would only print "%s %s" padded to sizeof(concat)-1. Next sizeof(concat)-1, will return sizeof(char*)-1. This is the difference between an array and a pointer.

Also there's not much point doing a malloc here, you know the strings are never gonna be longer than 160 characters, you've already hardcoded the buffer sizes, why not the destination buffer? malloc is slow in comparison to a stack allocate. Especially on a multi-threaded environment where malloc needs to acquire a mutex. Even then, under UNIX malloc usually involves a system call (brk/sbrk). I'm not saying malloc is bad, it is very good, it just doesn't seem appropriate for such simple example.


char str1[80];
char str2[80];
char concat[sizeof(str1) + sizeof(str2) + 1];
printf("Enter: ");
fgets(str1, sizeof(str1), stdin);
printf("Enter: ");
fgets(str2, sizeof(str2), stdin);

snprintf(concat, sizeof(concat)-1, "%s %s", str1, str2);

debiandude
09-19-2001, 07:45 PM
Yeah I am sorry I did that quickly and wasn't paying attention.

I shouldn't have even used the modifer %*s because I already mal for their lengths.

char string1[80];
char string2[80];
char concat[160];

fprintf(stderr, "Enter: ");
fgets(string1, sizeof(string1), stdin);
string1[strlen(string1)-1] = '\0';
fprintf(stderr, "Enter: ");
fgets(string2, sizeof(string2), stdin);
string2[strlen(string2)-1] = '\0';

sprintf(concat, "%s %s", string1, string2);


fprintf(stderr, "%s\n", concat);


[ 19 September 2001: Message edited by: debiandude ]

TheLinuxDuck
09-20-2001, 09:27 AM
Don't forget, when doing user input, to move the read pointer to the end of the users input. If you don't, you'll end up getting whatever didn't fit into the first string as the input for the second string. If you don't mind a function handling the allocating:


#define MAXBUFLEN 1024
char *getInput(const int length)
{
char temp[MAXBUFLEN];
int inputLen;
if(length&lt;1) return NULL;
//
fgets(temp,length&gt;MAXBUFLEN?MAXBUFLEN:length,stdin );
fseek(stdio,0L,SEEK_END);
inputLen=strlen(temp);
if(temp[inputLen-1]=='\n') temp[inputLen-1]='\0';
buffer=(char *)malloc(inputLen);
if(buffer!=NULL) strcpy(buffer,temp);
return buffer;
}


Or without internal malloc'ing..

#define MAXBUFLEN 1024
void getInput(char *buffer, const int length)
{
char temp[MAXBUFLEN];
int inputLen;
if(length&lt;1) {
buffer=NULL;
return;
}
//
fgets(temp,length&gt;MAXBUFLEN?MAXBUFLEN:length,stdin );
fseek(stdio,0L,SEEK_END);
inputLen=strlen(temp);
if(temp[inputLen-1]=='\n') temp[inputLen-1]='\0';
strcpy(buffer,temp);
}


[ 20 September 2001: Message edited by: TheLinuxDuck ]