How can heap objects use data from the stack? - c

I've declared the struct foo like this:
struct foo {
const char* name_lower;
const char* name_caps
//..
};
I dynamically create instances of foo on the heap and want to save a value in the name_lower and name_caps member variable. This is done by the function bar
void bar(foo* entry, const char* str, int delimiter_pos) {
char l[2] = {str[caps_pos-1], '\0'}; // create new string
char c[2] = {str[caps_pos+1], '\0'};
entry->name_lower = &l[0]; // assign these strings the foo instance
entry->name_caps = &c[0];
}
I am worried, because I don't know if this code is going to crash. The temporarily created arrays l and c will be saved on the stack. Once the function terminates the stack will be cleared up and c and l will probably disappear.
Does this mean that the foo instance will lose its names, i.e. its references? If so, how can I solve this problem?

Continuing from the comment, the easiest way to allocate/copy and assign the start address for new blocks of memory for l and c is to use strdup (from string.h):
void bar(foo* entry, const char* str, int delimiter_pos) {
char l[2] = {str[caps_pos-1], '\0'}; // create new string
char c[2] = {str[caps_pos+1], '\0'};
entry->name_lower = strdup (l); // assign these strings the foo instance
entry->name_caps = strdup (c);
}
Don't forget to free the memory allocated to entry->name_lower and entry->name_caps when no longer needed.

You should instead use char *l = (char *)malloc(2 * sizeof(char)); and then initialize it; similarly for char *c. Then set entry->name_lower = l; entry->name_caps = c;
When allocating make sure you check whether the allocation succeeded, i.e. whether malloc returned non-NULL address.
Make sure you free the memory after you don't need it anymore: free(entry->name_lower); free(entry->name_caps);.

It will not lose anything. The pointers in the struct will retain their value, but the content will change and you will eventually get SIGSEGV.
For the char * to persist, you need to allocate it on the heap too.
void bar(foo* entry, const char* str, int delimiter_pos) {
char * l = malloc(2);
char * c = malloc(2);
/* Check l and c for NULLs */
l[0] = str[caps_pos-1];
l[1] = '\0';
c[0] = str[caps_pos+1];
c[1] = '\0';
entry->name_lower = l;
entry->name_caps = c;
}
Remember that you should also free() the struct members when you will no longer need it.

If you have a limit on the length of your strings, you can use char arrays instead of pointers. In your example, all strings have a length of 1. Assuming your strings cannot be longer than that, you can use char[2] instead of char*:
struct foo {
char name_lower[2];
char name_caps[2];
//..
};
void bar(foo* entry, const char* str, int delimiter_pos) {
entry->name_lower[0] = str[caps_pos-1];
entry->name_lower[1] = '\0';
entry->name_caps[0] = str[caps_pos+1];
entry->name_caps[1] = '\0';
}
Historical note:
Because this is so easy to use, people got accustomed to this, and forced artificial limits on string length, leading to buffer overflows. If your strings are not limited, use dynamic allocation instead of char arrays.

Related

Allocing memory to array of strings

So, i'm tring to allocate memory to insert file names in it. I have my struct Estado defined like this:
typedef struct estado{
char modo;
char jogador;
char matriz[8][8];
int pretas;
int brancas;
char *nome[10];
int current;
} Estado;
I tried doing this:
Estado insereFicheiro(Estado estado , char* nome){
estado.nome[estado.current] = malloc(sizeof(char*));
estado.nome[estado.current++] = nome;
return estado;
}
What am i doing wrong ?
There's two problems with the code you show:
With
estado.nome[estado.current] = malloc(sizeof(char*));
you allocate only space for a pointer, not the whole string. This is like you creating an array of one pointer. You need to allocate space for the string itself, whose length you get from strlen, and also for the null-terminator at the end:
estado.nome[estado.current] = malloc(strlen(nome) + 1); // +1 for null-terminator
With
estado.nome[estado.current++] = nome;
you overwrite the pointer you created above. This is equivalent to e.g. int a; a = 5; a = 10; and then be surprised that a is no longer equal to 5. You need to copy the string, not the pointer:
strcpy(estado.nome[estado.current++], nome);
Of course, you need to free the memory you allocate later in your code, once you're finished with it.
And of course you should have some bound-checking to make sure you don't go out of bounds of the estado.nome array (i.e. a check for estado.current < 10).

Converting a character pointer to uppercase in C

I have a pointer:
char * name;
it contains the string "test:case"
And I'm calling another function with it, and trying to store it in a structure. However, I want to capitalize the entire string first, but It doesn't seem to work.
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
for(i=0; i< strlen(name); i++) {
name[i] = toupper(name[i]);
}
l->name = name;
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
Where List is a struct that has a member (char *) named name.
This however, seg faults. I can't go about using non pointers in my case. As I have to use pointers and not character arrays, I'm trying to use toupper in every value of the char pointer, however this doesn't seem to work.
You're getting a segfault because the original string is presumably a literal, and it's not modifiable. You need to make a copy of it first.
void func(char * name) {
List * l;
l = malloc(sizeof(List));
name = strdup(name); // make a copy of name
for (char *p = name; *p; p++) {
*p = toupper(*p);
}
l->name = name;
}
Note that when you later free l, you'll first need to free l->name.
Since you only set the pointer l->name to name, this will crash the moment the original name is no longer there (maybe it was only on the stack?) and l->name is accessed. You need to malloc() space the size of strlen(name)+1, copy name there and set l->name to that address.
You have allocated the List, but not the name string itself.
You need to do:
l=malloc(sizeof(List));
l->name=(char*)malloc(strlen(name)+1); // You need to cater for the the final null char.
There are a few additional issues with your code, here is the correct one (didn't compile it, probably close to okay):
void func(char *name) {
List * l;
l = (List*)malloc(sizeof(List));
l->name = (char*)malloc(strlen(name)+1);
for(char *r=name, char *w=l->name; *r; ++r,++w) {
*w = toupper(*r);
}
*++w='\0';
}
And at every iteration, this code does not evaluate again and again strlen, which would be very bad.
There are two mistakes in the code.
char * name
The variable name contains a pointer to a string (i.e., an array of char).
When you write this:
name[i] = toupper(name[i]);
you are changing the original char itens of the string, if it is not a pointer to a constant string. If that is the case, it is a segmentation fault.
The other mistake is here:
l->name = name;
You are just assigning to the variable within the structure the pointer which was passed on through the variable name to the function. You should make a copy, like this:
strcpy(l->name, name);
This functions copies all the contents from the second argument to the first.
But that's not a good solution. If name contains a pointer to a constant string, it's still segmentation fault.
I'll rewrite your code:
void func(char * name) {
int i;
List * l;
l = malloc(sizeof(List));
char *buffer[strlen(name)]; //buffer of the contents pointed by *name* to upper case, initialized as empty string
for(i=0; i< strlen(name); i++) {
buffer[i] = toupper(name[i]);
}
buffer[i] = '\0'; //closing the string in i = strlen(name)
strcpy(l->name, buffer);
//CALL A FUNCTION TO LATER FREE ALLOCATED MEMORY
}
That way, you manipulate a copy of the original string, and than you make a copy of the buffer to the variable in the structure.
If you do this:
l->name = buffer;
you're only copying a local pointer, which will be gone with the end of the function.
I suggest you learn more about pointers, arrays and strings in C. In essence, a string is a array of char, with a '\0' in the final position. An empty string s has '\0' in s[0].
Edit: if you're used to languages which makes a copy of the string like this:
string1 = string2
you should always have in mind that, in C, that's pointer assignment. So, in C, that code would have to be written like this:
strcpy(string1, string2);
Hope that helps.

Using strncpy() to copy const char *

I'm very new to C, I'm getting stuck using the strncpy function.\
Here's an example of what I'm working with:
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1 = malloc(sizeof(struct test));
strncpy(t1->name, s, sizeof(*s));
t1->name[NAMESIZE] = '\0';
printf("%s\n", t1->name);
}
I have a const char *, I need to set the "name" value of test to the const char. I'm having a really tough time figuring this out. Is this even the correct approach?
Thank you very much!
Well, you allocate the structure, but not the string inside the structure. You need to do that before you copy to it. Even when you do, you will probably overwrite unallocated memory when you attempt to set the string terminator.
And, due to a hight intake ow wine, I just noticed you actually only copy one character, but it's still undefined behavior.
Let's take this one step at a time:
struct test *t1 = malloc(sizeof(struct test));
this allocates space for a struct test; enough space for the pointer name, but not any memory for the pointer to point to. At a minimum, you'll want to do the following:
t1->name = malloc(strlen(s) + 1);
Having done that, you can proceed to copy the string. However, you already computed the length of the string once to allocate the memory; there's no sense in doing it again implicitly by calling strncpy. Instead, do the following:
const size_t len = strlen(s) + 1; // +1 accounts for terminating NUL
t1->name = malloc(len);
memcpy(t1->name, s, len);
In general, try to use this basic pattern; compute the length of strings once when they come into your code, but then use explicit-sized memory buffers and the mem* operations instead of implicit-length strings with str* operations. It is at least as safe (and often safer) and more efficient if done properly.
You might use strncpy if t1->name was a fixed-size array instead (though many people prefer to use strlcpy). That would look like the following:
struct test { char name[MAXSIZE]; };
struct test *t1 = malloc(sizeof *t1);
strncpy(t1->name, s, MAXSIZE - 1);
t1->name[MAXSIZE-1] = 0; // force NUL-termination
Note that the size argument to strncpy should always be the size of the destination, not the source, to avoid writing outside the bounds of the destination buffer.
Without any attempt at completeness or educational direction, here's a version of your code that should work. You can play "spot the difference" and search for an explanation for each one separately on this site.
int main()
{
const char s[] = "how"; // s is an array, const char[4]
struct test{ char name[NAMESIZE]; }; // test::name is an array
struct test * t1 = malloc(sizeof *t1); // DRY
strncpy(t1->name, s, NAMESIZE); // size of the destination
t1->name[NAMESIZE - 1] = '\0'; // because strncpy is evil
printf("%s\n", t1->name);
free(t1); // clean up
}
strncpy() is always wrong
if the result is too long, the target string will not be nul-terminated
if the target is too long (the third argument) , the trailing end will be completely padded with NULs. This will waste a lot of cycles if you have large buffers and short strings.
Instead, you cound use memcpy() or strcpy, (or in your case even strdup() )
int main()
{
const char *s = "how";
struct test {
char *name;
};
struct test *t1
size_t len;
t1 = malloc(sizeof *t1);
#if USE_STRDUP
t1->name = strdup(s);
#else
len = strlen(s);
t1->name = malloc (1+len);
memcpy(t1->name, s, len);
t1->name[len] = '\0';
#endif
printf("%s\n", t1->name);
return 0;
}

String concatenation without strcat in C

I am having trouble concatenating strings in C, without strcat library function. Here is my code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main()
{
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
char *b1=(char*)malloc(100);
strcpy(b1,"Ratnavel");
int i;
int len=strlen(a1);
for(i=0;i<strlen(b1);i++)
{
a1[i+len]=b1[i];
}
a1[i+len]='\0';
printf("\n\n A: %s",a1);
return 0;
}
I made corrections to the code. This is working. Now can I do it without strcpy?
Old answer below
You can initialize a string with strcpy, like in your code, or directly when declaring the char array.
char a1[100] = "Vivek";
Other than that, you can do it char-by-char
a1[0] = 'V';
a1[1] = 'i';
// ...
a1[4] = 'k';
a1[5] = '\0';
Or you can write a few lines of code that replace strcpy and make them a function or use directly in your main function.
Old answer
You have
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|0|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_]
b1 [R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_|_|_|_|_|_]
and you want
0 1 2 3 4 5 6 7 8 9 ...
a1 [V|i|v|e|k|R|a|t|n|a|v|e|l|0|_|_|_|_|_|_|_|_]
so ...
a1[5] = 'R';
a1[6] = 'a';
// ...
a1[12] = 'l';
a1[13] = '\0';
but with loops and stuff, right? :D
Try this (remember to add missing bits)
for (aindex = 5; aindex < 14; aindex++) {
a1[aindex] = b1[aindex - 5];
}
Now think about the 5 and 14 in the loop above.
What can you replace them with? When you answer this, you have solved the programming problem you have :)
char a1[] = "Vivek";
Will create a char array a1 of size 6. You are trying to stuff it with more characters than it can hold.
If you want to be able to accommodate concatenation "Vivek" and "Ratnavel" you need to have a char array of size atleast 14 (5 + 8 + 1).
In your modified program you are doing:
char *a1=(char*)malloc(100); // 1
a1 = "Vivek"; // 2
1: Will allocate a memory chunk of size 100 bytes, makes a1 point to it.
2: Will make a1 point to the string literal "Vivek". This string literal cannot be modified.
To fix this use strcpy to copy the string into the allocated memory:
char *a1=(char*)malloc(100);
strcpy(a1,"Vivek");
Also the for loop condition i<strlen(b1)-1 will not copy last character from the string, change it to i<strlen(b1)
And
a1[i]='\0';
should be
a1[i + len]='\0';
as the new length of a1 is i+len and you need to have the NUL character at that index.
And don't forget to free your dynamically allocated memory once you are done using it.
You cannot safely write into those arrays, since you have not made sure that enough space is available. If you use malloc() to allocate space, you can't then overwrite the pointer by assigning to string literal. You need to use strcpy() to copy a string into the newly allocated buffers, in that case.
Also, the length of a string in C is computed by the strlen() function, not length() that you're using.
When concatenating, you need to terminate at the proper location, which your code doesn't seem to be doing.
Here's how I would re-implement strcat(), if needed for some reason:
char * my_strcat(char *out, const char *in)
{
char *anchor = out;
size_t olen;
if(out == NULL || in == NULL)
return NULL;
olen = strlen(out);
out += olen;
while(*out++ = *in++)
;
return anchor;
}
Note that this is just as bad as strcat() when it comes to buffer overruns, since it doesn't support limiting the space used in the output, it just assumes that there is enough space available.
Problems:
length isn't a function. strlen is, but you probably shouldn't call it in a loop - b1's length won't change on us, will it? Also, it returns a size_t, which may be the same size as int on your platform but will be unsigned. This can (but usually won't) cause errors, but you should do it right anyway.
a1 only has enough space for the first string, because the compiler doesn't know to allocate extra stack space for the rest of the string since. If you provide an explicit size, like [100], that should be enough for your purposes. If you need robust code that doesn't make assumptions about what is "enough", you should look into malloc and friends, though that may be a lesson for another day.
Your loop stops too early. i < b1_len (assuming you have a variable, b1_len, that was set to the length of b1 before the loop began) would be sufficient - strlen doesn't count the '\0' at the end.
But speaking of counting the '\0' at the end, a slightly more efficient implementation could use sizeof a1 - 1 instead of strlen(a1) in this case, since a1 (and b1) are declared as arrays, not pointers. It's your choice, but remember that sizeof won't work for pointers, so don't get them mixed up.
EDIT: New problems:
char *p = malloc(/*some*/); p = /* something */ is a problem. = with pointers doesn't copy contents, it copies the value, so you're throwing away the old pointer value you got from malloc. To copy the contents of a string into a char * (or a char [] for that matter) you'd need to use strcpy, strncpy, or (my preference) memcpy. (Or just a loop, but that's rather silly. Then again, it may be good practice if you're writing your own strcat.)
Unless you're using C++, I wouldn't cast the return value of malloc, but that's a religious war and we don't need one of those.
If you have strdup, use it. If you don't, here is a working implementation:
char *strdup(const char *c)
{
size_t l = strlen(c);
char *d = malloc(l + 1);
if(d) memcpy(d, c, l + 1);
return d;
}
It is one of the most useful functions not in the C standard library.
You can do it using strcpy() too ;)
char *a = (char *) malloc(100);
char *b = (char *) malloc(100);
strcpy(a, "abc"); // initializes a
strcpy(b, "def"); // and b
strcpy((a + strlen(a)), b); // copy b at end of a
printf("%s\n",a); // will produce: "abcdef"
i think this is an easy one.
#include<stdio.h>
int xstrlen(char *);
void xstrcat(char *,char *,int);
void main()
{
char source[]="Sarker";
char target[30]="Maruf";
int j=xstrlen(target);
xstrcat(target,source,j);
printf("Source String: %s\nTarget String: %s",source,target);
}
int xstrlen(char *s)
{
int len=0;
while(*s!='\0')
{
len++;
s++;
}
return len;
}
void xstrcat(char *t,char *s,int j)
{
while(*t!='\0')
{
*t=*t;
t++;
}
while(*s!='\0')
{
*t=*s;
s++;
t++;
}
}
It is better to factor out your strcat logic to a separate function. If you make use of pointer arithmetic, you don't need the strlen function:
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* To completely get rid of this,
implement your our strcpy as well */
static void
my_strcat (char* dest, char* src)
{
while (*dest) ++dest;
while (*src) *(dest++) = *(src++);
*dest = 0;
}
int
main()
{
char* a1 = malloc(100);
char* b1 = malloc(100);
strcpy (a1, "Vivek");
strcpy (b1, " Ratnavel");
my_strcat (a1, b1);
printf ("%s\n", a1); /* => Vivek Ratnavel */
free (a1);
free (b1);
return 0;
}

Reversing a string in C

I know this has been asked thousands of times but I just can't find the error in my code. Could someone kindly point out what I'm doing wrong?
#include <stdlib.h>
#include <string.h>
void reverseString(char *myString){
char temp;
int len = strlen(myString);
char *left = myString;
// char *right = &myString[len-1];
char *right = myString + strlen(myString) - 1;
while(left < right){
temp = *left;
*left = *right; // this line seems to be causing a segfault
*right = temp;
left++;
right--;
}
}
int main(void){
char *somestring = "hello";
printf("%s\n", somestring);
reverseString(somestring);
printf("%s", somestring);
}
Ultimately, it would be cleaner to reverse it in place, like so:
#include <stdio.h>
#include <string.h>
void
reverse(char *s)
{
int a, b, c;
for (b = 0, c = strlen(s) - 1; b < c; b++, c--) {
a = s[b];
s[b] = s[c];
s[c] = a;
}
return;
}
int main(void)
{
char string[] = "hello";
printf("%s\n", string);
reverse(string);
printf("%s\n", string);
return 0;
}
Your solution is essentially a semantically larger version of this one. Understand the difference between a pointer and an array. The standard explicitly states that the behviour of such an operation (modification of the contents of a string literal) is undefined. You should also see this excerpt from eskimo:
When you initialize a character array with a string constant:
char string[] = "Hello, world!";
you end up with an array containing the string, and you can modify the array's contents to your heart's content:
string[0] = 'J';
However, it's possible to use string constants (the formal term is string literals) at other places in your code. Since they're arrays, the compiler generates pointers to their first elements when they're used in expressions, as usual. That is, if you say
char *p1 = "Hello";
int len = strlen("world");
it's almost as if you'd said
char internal_string_1[] = "Hello";
char internal_string_2[] = "world";
char *p1 = &internal_string_1[0];
int len = strlen(&internal_string_2[0]);
Here, the arrays named internal_string_1 and internal_string_2 are supposed to suggest the fact that the compiler is actually generating little temporary arrays every time you use a string constant in your code. However, the subtle fact is that the arrays which are ``behind'' the string constants are not necessarily modifiable. In particular, the compiler may store them in read-only-memory. Therefore, if you write
char *p3 = "Hello, world!";
p3[0] = 'J';
your program may crash, because it may try to store a value (in this case, the character 'J') into nonwritable memory.
The moral is that whenever you're building or modifying strings, you have to make sure that the memory you're building or modifying them in is writable. That memory should either be an array you've allocated, or some memory which you've dynamically allocated by the techniques which we'll see in the next chapter. Make sure that no part of your program will ever try to modify a string which is actually one of the unnamed, unwritable arrays which the compiler generated for you in response to one of your string constants. (The only exception is array initialization, because if you write to such an array, you're writing to the array, not to the string literal which you used to initialize the array.) "
the problem is here
char *somestring = "hello";
somestring points to the string literal "hello". the C++ standard doesn't gurantee this, but on most machines, this will be read-only data, so you won't be allowed to modify it.
declare it this way instead
char somestring[] = "hello";
You are invoking Undefined Behavior by trying to modify a potentially read-only memory area (string literals are implicitly const -- it's ok to read them but not to write them). Create a new string and return it, or pass a large enough buffer and write the reversed string to it.
You can use the following code
#include<stdio.h>
#include<string.h>
#include<malloc.h>
char * reverse(char*);
int main()
{
char* string = "hello";
printf("The reverse string is : %s", reverse(string));
return 0;
}
char * reverse(char* string)
{
int var=strlen(string)-1;
int i,k;
char *array;
array=malloc(100);
for(i=var,k=0;i>=0;i--)
{
array[k]=string[i];
k++;
}
return array;
}
I take it calling strrev() is out of the question?
Your logic seems correct. Instead of using pointers, it is cleaner to deal with char[].

Resources