string1=string2 changes value of string2 if I change string1

R

Rudra Banerjee

Dear friends,
I have a function,

static void mk_bib(GtkWidget *widget, gpointer data) {
if (!filename) {
caution("No File Selected");
} else {
char *bibstyl = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(bibcombo));
if (strcmp(bibstyl, "==select bibstyle==") == 0) {
caution("Select Bibliography style file");
} else {
char *p1 = filename;
char *p2 = rindex(p1, '.');
if (p2 != NULL) {
if (strcmp(p2, ".bib") == 0) {
*p2 = '\0';
}
}
g_print("Before basefn=Bibstyl=>%s\n",bibstyl);
char *basefn=bibstyl;
strcat(basefn, ".tex");
g_print("Before basefn=Bibstyl=>%s\n",bibstyl);
}
}
}

which, while running, changes value of bibstyl after strcat.
the result of two g_print is:

Before basefn=Bibstyl=>aabbrv
Before basefn=Bibstyl=>aabbrv.tex

Why it is so? Where I am doing wrong?
 
K

Kenny McCormack

Kiki will tell you any second now that C has no "string" data type.

Instead, it merely has (char) pointers, which most people treat as if they
were a string type, but in fact, they are not.

Once you understand this, it will become obvious why your program does what
it does.
 
J

James Kuyper

Dear friends,
I have a function,

static void mk_bib(GtkWidget *widget, gpointer data) {
if (!filename) {
caution("No File Selected");
} else {
char *bibstyl = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(bibcombo));
if (strcmp(bibstyl, "==select bibstyle==") == 0) {
caution("Select Bibliography style file");
} else {
char *p1 = filename;
char *p2 = rindex(p1, '.');
if (p2 != NULL) {
if (strcmp(p2, ".bib") == 0) {
*p2 = '\0';
}
}
g_print("Before basefn=Bibstyl=>%s\n",bibstyl);
char *basefn=bibstyl;
strcat(basefn, ".tex");
g_print("Before basefn=Bibstyl=>%s\n",bibstyl);
}
}
}

which, while running, changes value of bibstyl after strcat.
the result of two g_print is:

Before basefn=Bibstyl=>aabbrv
Before basefn=Bibstyl=>aabbrv.tex

Why it is so?

Because you set basefn to point at the same place that bibstyle points
at, and then passed that pointer value to strcat(). You told strcat()
to put it's output there. If you wanted it to put the output somewhere
else, you should have reserved some memory to put it into.

You have five basic choices, depending upon how long you want the memory
to last, and other issues. I'll demonstrate all five:

// You're responsible for setting ENOUGH_SPACE big enough.
#define ENOUGH_SPACE 128
char file_scope_static[ENOUGH_SPACE];

static void mk_bib(GtkWidget *widget, gpointer data)
{
static char block_scope_static[ENOUGH_SPACE];
char automatic[ENOUGH_SPACE];

// other code
{
// VLAs are only guaranteed to be supported in C99. They didn't
// exist in C90, and have been made optional in C2011.
char vla[strlen(bibstyle)+sizeof ".tex"];
char *dynamic = malloc(strlen(bibstyle)+sizeof ".tex");
if(dynamic)
{
char *basefn;
// At this point, you can set basefn to point a
// file_scope_static, block_scope_static, automatic, vla,
// or dynamic. Your choice.
#ifdef YOUR_WAY
strcpy(basefn, bibstyle);
strcat(basefn, ".tex");
#else // MY_WAY
sprintf(base fn, "%s.tex", bibstyle);
#endif
free(dynamic);
}
else
{
// out of memory error handling
}
}
}

Memory will be allocated for file_scope_static and block_scope_static
for the entire lifetime of your program.
Memory will be allocated for automatic and vla only during the lifetime
of the code block that they are defined in.
The memory pointed at by dynamic will remain allocated until you call
free(). If you never call free(), it will remain allocated until the
very end of your program, even after the variable named "dynamic" no
longer exists. This is called a memory leak, and should normally be
avoided - but there are situations where it's harmless, or at least
fairly well justified.

Which of these methods is appropriate depends upon how long you need the
memory to remain allocated. For your example code, I'd normally go with
automatic, but your actual code might need to hold onto the memory a
little longer than that.
 
K

Keith Thompson

Johann Klammer said:
you copied the pointer, not the string. They both(basefn and bibstyl)
point at the same string. Use strndup or something similar.

strndup() is a "safer" version of strdup(). Both strndup()
and strdup() are non-standard, so using either will limit the
portability of your code.

The usual way to copy the contents of a string, rather
than copying a pointer to it, is the strcpy() function --
but it won't allocate memory for you, nor will it check
that there's enough room in the target array. (strncpy()
is *not* a safer verison of strcpy(); it's a very different
function that's rarely useful. I've written about it at
<http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html>.)
 
K

Kaz Kylheku

strndup() is a "safer" version of strdup(). Both strndup()
and strdup() are non-standard, so using either will limit the
portability of your code.

That's nonsense. What limits the portability of code is what is actually
implemented, not what is standard.

The standard is just a pile of paper. Moreover, the latest few revisiosn of it
describe an imaginary language that is not completely implemented anywhere.
Thus, some non-standard things are actually more widely portable than
some standard ones. For example, strdup will work on Unix-like systems and
Microsoft Visual C, whereas some "standard" C99 features will not.

You can easily use preprocessor symbols to capture a configuration, which
informs your program about what functions are not available and have
to be reimplemented locally:

/* header */
#if !HAVE_STRNDUP
extern char *strdup(const char *); /* your own declaration */
#endif

/* C file */
#if !HAVE_STRNDUP
char *strdup(const char *in)
{
/* your own implementation */
}
#endif

See, now it's portable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top