So I am new to C and I have a question that I am hoping someone can help me with. Suppose I have a string.
typedef struct String {
char *value;
int size;
} String;
And what I want to do is initialize this string with a function. My first question is which would be better
bool init_String(String **s, char *p) {
if (s == NULL || *s == NULL) {
return false;
}
(*s)->value = p;
(*s)->size = strlen(p);
return true;
}
In this version the function takes a pointer to a pointer and doesn't return the string. My other version is this one:
String *init_String(String **s, char *p) {
if (s == NULL) {
return NULL;
}
s->value = p;
s->size = strlen(p);
return s;
}
Which is better for the user? My second question is is it better to malloc according to the user or according to me. In other words should the user malloc a String and then pass it to the init function or should the init function work as alloc_init and do both the call to malloc and the string initialization?
Thanks
How about this?
typedef struct String {
char *value;
size_t size;
int ref; // if nonzero, do not free(value)
} String;
String refer_String(const char *p) {
String out = { p, strlen(p), 1 };
return out;
}
String copy_String(const char *p) {
String out = { strdup(p), strlen(p), 0 };
return out;
}
void free_String(const String *s) {
if (!s->ref) {
free(s->value);
}
}
This provides a way to refer to existing literal strings like your original code, but also a way to create new strings which may be modified.
Related
I have a stack implementation that stores variable: char *items on the stack. But for some reason when I use stack->items[position], it treats it as a regular char (not a pointer) and I am unable to store the full char (it is a URL) on the stack.
I want to give the push function a char * (that is a URL) and I want to take that and put in on my stack, that is either:
p->items[p->pos] = item;
or
strcpy(p->items[p->pos], item);
Here is the part of the code that gives the error:
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "shm_stack.h"
typedef struct int_stack{
int size; /* the max capacity of the stack */
int pos; /* position of last item pushed onto the stack */
char *items; /* stack of stored chars */
} ISTACK;
int is_full(ISTACK *p){
if ( p == NULL ) {
return 0;
}
return ( p->pos == (p->size -1) );
}
int sizeof_shm_stack(int size){
return (sizeof(ISTACK) + sizeof(char) * size);
}
int init_shm_stack(ISTACK *p, int stack_size){
if ( p == NULL || stack_size == 0 ) {
return 1;
}
p->size = stack_size;
p->pos = -1;
p->items = (char *) (p + sizeof(ISTACK));
return 0;
}
ISTACK *create_stack(int size){
int mem_size = 0;
ISTACK *pstack = NULL;
if ( size == 0 ) {
return NULL;
}
mem_size = sizeof_shm_stack(size);
pstack = malloc(mem_size);
if ( pstack == NULL ) {
perror("malloc");
} else {
char *p = (char *)pstack;
pstack->items = (char *) (p + sizeof(ISTACK));
pstack->size = size;
pstack->pos = -1;
}
return pstack;
}
void destroy_stack(ISTACK *p){
if ( p != NULL ) {
free(p);
}
}
int push(ISTACK *p, char *item){
if ( p == NULL ) {
return -1;
}
if ( !is_full(p) ) {
++(p->pos);
//p->items[p->pos] = item;
strcpy(p->items[p->pos], item);
//printf("push method: %d\n", p->items[p->pos]);
return 0;
} else {
return -1;
}
}
The issue is in my push method where I can neither use strcpy() or just assign the char to p->items[p-pos] without it saying something like "assigning char from incompatible type char *", but dereferencing "item" will only get me the first character, and I want the entire "string".
Why is this happening and how can I fix it?
p->items is a char*, so p->items[...] is a char. strcpy expects a char*, so there's a mismatch between what you provide and what's needed.
Not only that, it expects the pointer to point to the first of enough characters to contain the string being copied in. You did not even attempt to get the length of the string pointed by item, much less allocate enough memory for it.
I presume you want a stack of strings. If so, we need a array of pointers (char *items[]) or a pointer to a block of memory for pointers (char **items). The latter is simpler here. As such,
char *items;
should be
char **items;
It would be allocated using
malloc(sizeof(char*) * size)
There are two approaches to adding a string to the stack.
The stack could take ownership of the string provided.
p->items[p->pos] = item;
The stack could make a copy of the string provided.
p->items[p->pos] = strdup(item);
The difference is in who is responsible for freeing the string.
Desired outcome:
utilityfun("&xxx") must return a pointer to "xxx".
utilityfun("xxx") must return a pointer to "*xxx".
#include <stdio.h>
#include <string.h>
char* utilityfun(char *s)
{
if(*s=='&')
return s+1; // this case works fine
else
{
char r[strlen(s)+2];
memset(r,'*',1);
strcpy(r+1,s);
char* p=r;
return p; // !!! p is local to this stack frame!
}
}
void main()
{
char* q=utilityfun("xxx");
printf("%p\n",q);
printf("%s\n",q); // *xxx It seems to work if I use q right way, but...
utilityfun("eee");
printf("%s\n",q); // *eee
}
Allocating a new char array on the heap is the only way?
My problem with that is: being utilityfun a utility function, I don't want to have to free memory outside of it each time I use it. Is there a way?
Given that it only needs to work with string literals… you can use a macro.
#include <stdio.h>
#define utilityfun(x) utilityfun_("*" x)
char *utilityfun_(char *s) {
if (s[0] == '*' && s[1] == '&') {
return s + 2;
}
return s;
}
int main(int argc, char **argv) {
char *a = utilityfun("eee");
char *b = utilityfun("&fff");
// Prints "a = *eee; b = fff;\n"
printf("a = %s; b = %s;\n", a, b);
}
This is a pretty ugly hack but it doesn't allocate memory at runtime. It only works with string literals, because it uses string literal concatenation to avoid allocating—in C, "abc" "def" becomes "abcdef". This does not work with non-literals, e.g., "abc" x does not work.
You can define a public variable then fill and return it in function :
char *out;
char* utilityfun(char *s)
{
if(*s=='&')
return s+1; // this case works fine
else
{
// char r[strlen(s)+2]; // You cannot use of non-constant array length
char *r = (char*)malloc(strlen(s) + 2);
memset(r,'*',1);
strcpy(r+1,s);
strcpy(out, r); // Instead of char* p=r; use of this
free(r); // Then free r
return out;
}
}
In main function, allocate it to get the right size :
void main()
{
char *input = "xxx";
out = (char*)malloc(strlen(input) + 1);
char* q=utilityfun(input);
printf("%p\n",q);
printf("%s\n",q);
}
I think Dietrich's solution is the best for my problem, but would this be an alternative solution? Are there major drawbacks to this approach?
{
static char arr[10];
strncpy(arr,s,9);
if(arr[0]=='&')
{
return arr+1;
}
else
{
memcpy(&arr[1],&arr[0],strlen(s)+1);
arr[0]='*';
return arr;
}
}
A way of ending a char array before it becomes full is to put '\0' at end, like-
single_str[5] ='\0';
Then how to end a 2D char array in that way?
In practice, you should in C avoid thinking of 2D arrays. Stricto sensu, the C language don't know about 2D arrays, only about arrays of arrays (fixed length, all of the same size) or about arrays of pointers (or array of aggregates or scalars).
You might use an array of string pointers. C strings are conventionally ended by a zero byte. Here is an example of constant array (of constant strings, i.e. const char* pointers) ended by a NULL string
const char*const arrstr[] = {
"Hello",
"Nice",
"World",
NULL
};
On my machine, sizeof(const char*) is 8, so sizeof(arrstr) is 32; and sizeof("Nice") is 5.
You could print all the array members with
for (const char*const* p = arrstr; *p; p++) printf("%s\n", *p);
You could use in C99 a structure ending with a flexible array member, e.g.
struct my_string_array_st {
unsigned len;
char* arr[]; // array of len pointers */
};
then you might have a constructor function which build such string arrays with empty content like
struct my_string_array_st* make_string_array(unsigned ln) {
struct my_string_array_st*p
= malloc(sizeof(struct my_string_array_st) + len*sizeof(char*));
if (!p) { perror("malloc"); exit(EXIT_FAILURE); };
p->len = ln;
for (unsigned ix=0; ix<ln; ix+) p->arr[ix] = NULL;
return p; }
you'll then decide (this is your convention to follow) that each string inside is heap-allocated with strdup - so you don't have two aliased pointers inside. Here is the function to set a string (and release the previous one, if needed)
void
set_string_array(struct my_string_array_st*p, unsigned ix, const char*str) {
if (!p || ix>=p->len) return;
free(p->arr[ix]);
char* s = NULL;
if (str) {
s = strdup(str);
if (!s) { perror("strdup"); exit(EXIT_FAILURE); };
};
p->arr[ix] = s;
}
(recall that you are allowed to free(3) a NULL pointer; it is a no-op)
and here is a destructor function, releasing all the internal strings.
void destroy_string_array(struct my_string_array_st*p) {
if (!p) return;
unsigned l = p->len;
for (unsigned ix=0; ix<l; ix++) free(p->arr[ix]);
free (p);
}
Of course, here is an accessor function:
const char* nth_string_array(struct my_string_array_st*p, unsigned ix)
{
if (!p || ix>=p->len) return NULL;
return p->arr[ix];
}
You can use an empty string "":
#include <stdio.h>
int main(void)
{
char arr[][3] = {"ab", "cd", ""};
char (*p)[3] = arr;
while (**p) { /* while not an empty string */
printf("%s\n", *p);
p++;
}
return 0;
}
If arr can contain an empty string, you can use a non printable character, like ETX (end of text):
#include <stdio.h>
int main(void)
{
char arr[][3] = {"ab", "", "\x03"};
char (*p)[3] = arr;
while (**p != '\x03') {
printf("%s\n", *p);
p++;
}
return 0;
}
For a a non modifiable array you can use NULL:
#include <stdio.h>
int main(void)
{
char *arr[] = {"ab", "cd", NULL}; /* Read only */
char **p = arr;
while (*p) { /* while not NULL */
printf("%s\n", *p);
p++;
}
return 0;
}
You need to define a sentinel value.
As sentinel for linear and scattered arrays this can be any valid C-"string", which is known to not be used as play-load value during operation for any of the array's elements.
For scattered arrays also NULL can be used as sentinel.
Example for linear array
Define the sentinel value:
#define END_OF_ARRAY "__EOA__"
or just the empty "string":
#define END_OF_ARRAY ""
Note that the sentinel has to be a C-"string" when used with a linear array!
char array [][8] = {
"1st",
"2nd",
END_OF_ARRAY
}
To detect the array's size you then might use a function like this:
ssize_t get_array_size(const char (*parray)[][8])
{
ssize_t s = -1;
if (NULL == parray)
{
errno = EINVAL;
}
else
{
s = 0;
while (strcmp((*parray)[s], END_OF_ARRAY))
{
++s;
}
}
return s;
}
Example for scattered array
Define the sentinel value:
#define END_OF_ARRAY NULL
or also possible
#define END_OF_ARRAY "__EOA__"
Note that commonly NULL is used.
char * array[] = {
"1st",
"2nd",
END_OF_ARRAY
}
To detect the array's size you then might use a function like this:
ssize_t get_array_size(const char *** parray)
{
ssize_t s = -1;
if (NULL == parray || NULL == *parray)
{
errno = EINVAL;
}
else
{
s = 0;
while ((*parray)[s] != END_OF_ARRAY)
{
++s;
}
}
return s;
}
Usage
For both examples call it like this:
int main(void)
{
ssize_t result = get_array_size(&array);
if (-1 == result)
{
perror("get_array_size() failed");
}
else
{
size_t size = result;
printf("number of elements: %zu\n", size)
}
return 0;
}
Simpler approach for scattered arrays
Define the sentinel value:
#define END_OF_ARRAY NULL
or also possible
#define END_OF_ARRAY "__EOA__"
Note that commonly NULL is used.
char * array[] = {
"1st",
"2nd",
END_OF_ARRAY
}
To detect the array's size you then might use a function like this:
ssize_t get_array_size(const char ** parray)
{
ssize_t s = -1;
if (NULL == parray)
{
errno = EINVAL;
}
else
{
s = 0;
while (parray[s] != END_OF_ARRAY)
{
++s;
}
}
return s;
}
Usage
Note when calling this simpler implementation the array is passed directly and not its address is being passed:
int main(void)
{
ssize_t result = get_array_size(array);
if (-1 == result)
{
perror("get_array_size() failed");
}
else
{
size_t size = result;
printf("number of elements: %zu\n", size)
}
return 0;
}
You can assign like this.
char ar[3][20];
ar[2][0]='\0';
You can place the null at which position you need. Consider you need to place the null in 1th line 10th column you can do like this.
ar[1][10]='\0';
Like this where you need to place the null you can place the null.
I have 1 function that I want to return the address of an assigned string to the main function and assign an new string pointer with the same address so that the new string will have the contents of the old string.
For example:
unknown_datatype function()
{
char *old = "THE STRING";
return old;
}
int main()
{
char *snew = "";
snew = function();
return 0;
}
*unknown_datatype means I don't know that to put there...
*How can I approach this without changing anything in the main() method
Typically you will pass the address of the first element in an array of chars in, as well as the length, and have the function fill it.
int fillMyString(char *str, int buffer_size)
{
if(buffer_size > strlen("test"))
{
strncpy(str, "test", buffer_size-1);
str[buffer_size-1] = '\0';
return strlen(str);
}
return 0;
}
//In some function or main
char buffer[1024];
fillMyString(buffer, 1024);
ASSERT(!strcmp(buffer, "test"));
Edit: You mentioned that for some reason you need to return a char*. I would suggest in that case to use malloc to allocate the string inside the function, but make sure whenever you call the function you free the return value eventually.
You can simply return a char*. Since you are returning a pointer to a string literal, it's probably best to return a const char*, since you aren't able to modify the string literal:
const char* function()
And likewise you would want to assign the return value to a const char*:
const char* snew = 0;
snew = function();
The unknown data type would have to be char* but in this case it would not do what you expect since the variables in function() are local variables that will disappear once the function exits and they get popped off the stack. You could use a malloc() call inside the function and return a pointer to the new string. Just don't forget to free it when you're done with it.
OK here is the answer: Since I cannot EDIT the main (MEANING I CANNOT PASS ANY PARAMETER) the following solution is possible:
char *function()
{
char *old;
old = (char*)malloc(9999);
strcpy(old,"THE STRING");
return old;
}
int main()
{
char *snew = "";
snew = function();
return 0;
}
Thanks for all who replied.
As Brian pointed out, the most idiomatic thing to do in C is to pass a buffer, so you would do:
int give_me_a_string(char* buffer, int buffersize)
{
const char* result = "Hello world!";
int requiredbufferlen = strlen(result)+1;
if ( (buffer==0) || (buffersize<requiredbufferlen) ){
errno = EINVAL;
return -1;
}
strncpy(buffer,"Hello world!",buffersize);
buffer[buffersize-1]='\0';
return 0;
}
int main(int argc, char* argv[])
{
int buffersize = 256;
char* buffer = (char*) malloc(buffersize);
if ( buffer == 0 ){
printf("Out of memory!\n");
return 1;
}
if ( give_me_a_string(buffer,buffersize) < 0 ){
printf("Oh my god, there's an error!\n");
free(buffer);
return 1;
}else{
printf("%s\n",buffer);
}
free(buffer);
return 0;
}
Now, if you absolutely have to not pass in the buffer, then you could write:
char* give_me_a_string(void)
{
const char* str="Hello world!";
int buffersize = strlen(str)+1;
char* result=(char*) malloc(buffersize);
if ( result == 0 ){
return 0;
}
strncpy(result,str,buffersize);
result[buffersize-1]='\0';
return result;
}
However, if you use the above, then you have to remember to free() the result. However, I strongly suggest you use the former approach; when a function return a pointer object, it is not clear who has ownership (i.e. who is responsible to deallocate the string). By requiring the caller to pass in the buffer, you make that ownership explicit (i.e. the caller owns the buffer and must deallocate it himself/herself).
There is one last solution that you can use. If you are returning a constant string, then this is acceptable; however, if you need to compute the string, doing this makes it non-reentrant, and so I would highly advise against doing it. Actually, I would highly advise against this solution even if you were returning a constant string, because then the API cannot adapt to the case where you do need to compute the string. This method is to use a shared global variable that contains the result, so it would be like:
// declaration
char* give_me_a_string(void);
// implementation
char* global_string = "Hello world!";
char* give_me_a_string(void)
{
return global_string;
}
This last solution doesn't require any deallocation, because the function, itself, is the owner. If you were doing this with a computed string, it would look like:
// declaration
char* give_me_a_string(void);
// implementation
char* global_string = 0;
static void deallocate_global_string()
{
free(global_string);
global_string=0;
}
char* give_me_a_string(void)
{
if ( global_string == 0){
// allocate global_string
// ...
// initialize global_string
// ...
// ensure it is eventually freed
atexit(&deallocate_global_string);
}
return global_string;
}
As should be obvious, if you do this it is non-reentrant (it won't work with multiple threads), and so it is a really, really terrible idea. If you get burned, let me just say, I warned you.
char * function()
{
char *old = "THE STRING";
return old;
}
int main()
{
char *snew = "";
snew = function();
return 0;
}
Your question and example are contradicting each other.
Is this what your looking for ? given below are two simple solutions.
char* func(char *);
int main()
{
char *newstring="Hey";
newstring = func(newstring);
printf("New string : %s\n", newstring);
}
char* func(char *s)
{
printf("Old string : %s\n", s);
s="Hello";
return(s);
}
or else the solution given by Y_Y is also fine, assuming your string is created in the function call. Just in case you do not want to use malloc, the solution below works.
char* func();
int main()
{
char *newstring="";
newstring = func();
printf("New string : %s\n", newstring);
}
char* func()
{
char *s="Hello";
printf("Old string : %s\n", s);
return(s);
}
I have been cutting my teeth for the past 48 hours or so trying to implement this hash table function in C. My code is rather long (I realize it is not the most efficient, some of it is more me playing around with C to get a feel for how it works etc).
The problem I am having is with the last line of my main program at the bottom (printing MyEntry->Name). I am receiving a bus error and am unsure why. I do not believe I am supposed to allocate memory in the main driver for this pointer but I could be wrong.
Sorry about the length of this code. BTW SymEntry is 'struct SymEntry{char *Name, void *Attributes, struct SymEntry *Next}
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include "SymTab.h"
struct SymTab * CreateSymTab(int Size)
{
struct SymTab *symtable;
if(!(symtable=malloc(sizeof(struct SymTab)))) return NULL;
if(!(symtable->Contents=calloc(Size, sizeof(struct SymEntry*)))) {
free(symtable);
return NULL;
}
symtable->Size=Size;
return symtable;
}
/* hash form hash value for string s, taken from 'The C Programming Language'*/
unsigned hash(struct SymTab *ATable, const char *s)
{
unsigned hashval, size;
size = ATable->Size;;
for (hashval = 0; *s != '\0'; s++)
hashval = *s + 31 * hashval;
return hashval % size;
}
bool EnterName(struct SymTab *ATable,
const char *Name,
struct SymEntry **AnEntry)
{
struct SymEntry *ptr;
unsigned hashvalue;
char *string;
struct SymEntry *previous;
string = malloc(strlen(Name)+1);
AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));
strcpy(string, Name);
printf("string is: is %s\n",string);
hashvalue = hash(ATable, string);
printf("hv is %d\n",hashvalue);
ptr = ATable->Contents[hashvalue];
previous = NULL;
while(ptr)
{
printf("WHILE LOOP\n");
if(!(strcmp(ptr->Name,string)))
{
printf("if(!strcmp(ptr->Name,string))\n");
*AnEntry = ptr;
return true;
}
previous = ptr;
ptr=ptr->Next;
}
if(previous)
{
printf("IF (PREVIOUS)\n");
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
previous->Next = ptr;
printf("Previous->Next: %s\n", previous->Next->Name);
*AnEntry = ptr;
return false;
}
else
{
printf("ELSE (PREVIOUS)\n");
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
ATable->Contents[hashvalue] = ptr;
printf("here\n");
*AnEntry = ptr;
printf("there\n");
return false;
}
}
struct SymEntry * FindName(struct SymTab *ATable, const char *Name)
{
struct SymEntry *Entry;
unsigned hashvalue;
hashvalue = hash(ATable, Name);
Entry = ATable->Contents[hashvalue];
while(Entry)
{
if(strcmp(Name,Entry->Name)==0)
{
return Entry;
}
}
return NULL;
}
main(int argc, char **argv)
{
struct SymTab *mysymtab;
struct SymEntry *myEntry;
mysymtab = CreateSymTab(1);
const char *string1 = "HELLO";
printf("%d\n",6);
EnterName(mysymtab, string1, &myEntry);
printf("first: %s\n", mysymtab->Contents[0]->Name);
EnterName(mysymtab, string1, NULL);
EnterName(mysymtab, "WORLD", NULL);
printf("second: %s\n", mysymtab->Contents[0]->Name);
printf("second->Next: %s\n", mysymtab->Contents[0]->Next->Name);
EnterName(mysymtab, "!##$%", &myEntry);
printf("third: %s\n", mysymtab->Contents[0]->Name);
printf("third->Next: %s\n", mysymtab->Contents[0]->Next->Name);
printf("third->Next->Next: %s\n", mysymtab->Contents[0]->Next->Next->Name);
printf("myEntry->Name: %s\n", myEntry->Name);
}
The problem is this line in EnterName:
AnEntry=(struct SymEntry**)malloc(sizeof(struct SymEntry*));
You need to remove that as you want AnEntry to point to the argument that the caller specified.
Because AnEntry may be NULL, you will also need to change every instance of:
*AnEntry = ptr;
to:
if (AnEntry)
*AnEntry = ptr;
What is happening is that when the function starts, AnEntry is pointing to the pointer the caller wants to change. When you change the value of AnEntry (i.e AnEntry = ...;), your code will not modify the pointer the caller want you to change but some internal pointer. Therefore, when EnterName returns, myEntry is still pointing to some random place in memory.
While you're at learning, there are some stylistic WTFs in your code. Take this part, for example.
if(!(ptr=malloc(sizeof(struct SymEntry)))) return false;
if(!(ptr->Name=string))
{
printf("if(!(ptr->Name=string))\n");
free(ptr);
return false;
}
ptr->Name = string;
It's inconsistent. You cast the return of malloc for AnEntry above, but not this malloc. Either do one or the other, but don't mix it. Better yet, write it in a way that doesn't "need" a cast at all.
You shouldn't assign values within if-statements. While it is still clear what you want to do in the malloc-case, the intention is obfuscated in the string assignment. Especially since it is superfluous. When the if evaluates to true, ptr is immediately freed. When it evaluates to false, the exact same assignment is done again. Additionally, in this case it prevents an obvious optimization.
Here is the same code rewritten:
if (string == NULL)
{
printf("string == NULL\n");
return false;
}
ptr = malloc(sizeof *ptr);
if (ptr == NULL)
{
return false;
}
ptr->Name = string;