Passing pointer and copy value - c

I guess I do something stupid here, please help me understand what it is, i get a crash :
char *data="xyz";
int EEIndex=0;
int getEEPROMindex();
void updateEEPROMindex();
void getCmd(char *cmd);
void getcmdAtIndex(int index,char *cmd);
int main(int argc, const char * argv[]) {
getCmd(data);
printf("%s ",data );
return 0 ;
}
void getCmd(char *cmd)
{
getcmdAtIndex(EEIndex, cmd);
}
void getcmdAtIndex(int index,char *cmd)
{
char *EEPROM[]={"A","E","C","D"};
strcpy(cmd, EEPROM[index]);
EEIndex=index+1;
}

It's customary to make string literals read-only. That is:
char *data="xyz";
when your code tried to change the bytes x, y and z, the OS crashes it.
To make it writable, replace a pointer with an array; you should also specify the size of the array. The easiest method to do it is:
char data[] = "xyz"; // will hold a maximum of 3 bytes (size is implicit)
or
char data[20]; // will hold a maximum of 19 bytes plus an end-of-string byte
You can also use strdup:
char* data;
...
strdup(cmd, EEPROM[index]); // instead of strcpy
but this involves dynamic memory allocation, which I think you don't want to bother with.

You're strcpying into static memory space, i.e.
char *data="xyz";
That is, you created a string xyz that was stored in a reserved memory location at compile-time. You can't write into that memory location. You want to allocate new space, e.g. malloc.

char *data="xyz"; defines a char pointer to "xyz" which is located in read-only area so you can't write to this place. What point you still persist?
Change it to char data[] = "xyz" ensures this literal is copied to stack - so it's modifiable.
In addition, getcmdAtIndex function is not safe. What about out of index position?

Related

Returning a string (char array, char pointer etc.) from a function

I am writing a program for ESP8266 on Arduino SDK. My C knowledge is not enough to create professional project so I am training my self about C programming concepts now.
I deep dive to pointers and I tried write a function that return one float value and one string value. I used pointers to do that. For float, everything went well but I cannot return string value.
Here is the my code:
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
sprintf(v_str, "%s", v_str);
sGross = v_str;
}
What is the point that I missed? My char value null or esp8266 restarting?
An option is to directly copy into the sGross.
dtostrf(*fGross, 5, 2, sGross);
Then you have to be sure the function calling has allocated enough memory.
void main()
{
float val1;
char val2[10];
returnMultiple(&val1, val2);
}
The end result will then be
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
If you define an interface you do not only need to specify the function signature but also how to call it.
Typical questions are:
What type of memory is used for buffers
Who will allocate the memory
Who will free the memory
If you define that the caller has to provide the buffer, your code could look like this:
void returnMultiple(float *fGross, char *sGross)
{
if (fGross == NULL || sGross == NULL)
return;
*fGross = 50.0;
dtostrf(*fGross, 5, 2, sGross);
}
void callerfunc(void)
{
char buf[10];
float flt;
returnMultiple(&flt, buf);
printf("flt: %f; str: %s\n", flt, buf);
}
As no dynamic memory allocation is done, nothing needs to be freed.
You might define another return type to allow for error indications.
You assign to sGross pointer the value of local variable v_str... but that data will be destroyed as soon as the function returns (it is stored in the stack, so it will be overwritten).
What you need to do is to allocate the buffer externally. You can either
Use dynamic memory with something like char *str = malloc(10 * sizeof(char)); (remembering to free it as soon as it is no more needed).
Define externally an array of chars, like in the example below
float val1;
char val2;
void returnMultiple(float *fGross, char *sGross)
{
*fGross = 50.0;
char v_str[10];
dtostrf(*fGross, 5, 2, v_str);
/* CHANGES HERE! */
sprintf(sGross, "%s", v_str);
// No need to assign to sGross the pointer of a local variable
// sGross = v_str;
}
int main( void )
{
char testString[10];
float testFloat;
returnMultiple(&testFloat, testString);
printf("%s\n", testString);
return 0;
}
In this case I would suggest to pass not only the char pointer, but also the size of the buffer.
Another solution is allocating the char array within returnMultiple() function, returning the pointer to the char array. sGross parameter in this case would become a char ** variable.
But I suggest starting with easier solutions like the one showed in my example.
First: Your problem is with the way you return the string, not the float, so I'm reducing my example to just returning the string.
There are two ways you can implement this: Either the memory for your string is allocated by the function, or by the caller. The easy way is this:
void toString(char *str, int d) {
sprinf(str, "%d", d);
}
int main(void) {
char result[12];
toString(result, 50);
puts(result, stdout);
return 0;
}
In this case, result is a 12 byte string allocated on the stack of main. 12 bytes is big enough to store the string representation of an integer, so that's safe, if you're not sure what size the result can have, then watch out.
Second option:
void toString(char **str, int d) {
char *v_str = malloc(12);
sprintf(v_str, "%d", d);
*str = v_str;
}
int main(void) {
char *result;
toString(&result, 50);
puts(result, stdout);
free(result);
return 0;
}
In this case, we pretend that the caller doesn't know how much memory is required for the result string, and let the toString function decide. It allocates as much memory as it needs for the conversion, then returns the allocated string. The caller needs to release that memory with free. Note that we've got to pass the address &result in this situation, so toString will write the pointer to the allocated string into our result variable. Double pointers like this can seem confusing to some people who are new to C, but it's conceptually similar to how you're passing a pointer to your float variable (float *fGross).
Personally, I prefer the first version when possible, because allocating memory on the stack avoids having to manage heap memory with malloc and free, a common source of memory leaks, especially for beginners. Of course, nothing prevents you from calling that version of toString with heap-allocated memory if you need to.

difference between creating an array "normally" and with malloc

I was messing with C pointers to pointers in functions to learn. I created a string array, and wanted to change it in the function foo with a pointer to pointer. I then print it, just to see.
Problem is: if I create it "normally": char array[] = "yeah", the code doesn't work and I see a bunch of weird characters on the console. But, If I create it with a malloc, it works. I really want to understand the difference.
This works:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void foo(char **ptr);
int main(int argc, char *argv[]) {
char *array = malloc(sizeof("yeah")); //I need to malloc here, or it doesn't work. Why ?
strcpy(array, "yeah");
printf("array before : %s \n", array);
char *ptr = array;
char **pt = &ptr;
foo(&array);
printf("array after : %s \n", array);
free(array);
}
void foo(char **ptr) {
char *truc = malloc(sizeof(char) * 20); //I need to malloc here, else it doesn't work. Why ?
strcpy(truc, "then");
*ptr = truc;
}
but this doesn't, it prints nasty characters on the console:
void foo(char **ptr);
int main(int argc, char *argv[]) {
char array[] = "yeah"; //created "normally"
printf("array before : %s \n", array);
char *ptr = array;
char **pt = &ptr;
foo(&array);
printf("array after : %s \n", array);
free(array);
}
void foo(char **ptr) {
char truc = "then";
*ptr = truc;
}
What is the difference between:
char array[] = "yeah";
and
char *array = malloc(sizeof("yeah");
strcpy(array, "yeah");
The Array Way
First thing you should note: The code: char array[] = "yeah"; will work.
Note: if you do this, you do not call free(array) because it is not a pointer to dynamically-allocated memory, and does not need to be dynamically returned to the heap. It exists on the stack. Read on...
But the function foo() here is the problem. When foo() is called, the string truc (which also could be declared char truc[] = "then";) exists in a stack frame, which is a section of program memory, which only exists until foo() returns. If you change array to point to memory within that stack frame, what happens when that function returns? That stack frame becomes undefined, and you're left pointing at junk memory.
If you want to change the contents of the string in array, you could ensure the buffer is long enough, and foo() could strcpy(array, "then") into it. So, you're not changing the pointer itself, just the memory it points to. This isn't what I'd call good software design, but for the sake of an example, it would work for you. Like this:
void foo(char * ptr)
{
strcpy(ptr, "then");
}
So why doesn't it work without malloc() in main()?
When you don't malloc() in main(), array represents, as it suggests, an array. The identifier is not itself a pointer, it is an array; however, it decays to a pointer, or if you will, acts like one. That's why you could pass it off as one, if you wanted, like if you passed it to foo(). Now, if you reference the address of array, like &array, (char*)array, &array, &array[0] are all the same - pointers to the beginning of array. Your foo() is actually writing a memory address to the memory of array, in this case.
What does this do? Well, the technical answer is undefined behavior. But I would guess that it's writing a 32-bit integer (a memory address) to a chunk of memory that used to represent 4 8-bit characters in a string. So now you've corrupted exactly four characters. And, if foo() is using malloc() as you show, also introduced a memory leak.
The neat part of this is that your string is exactly four characters, so this shouldn't corrupt the null terminator '\0' at the end of the string. Let me guess, you see exactly four junk characters?

Xcode Exc_BAD_ACCESS

so this code is giving me the Exc_bad_access_code(2) error and i have no idea why. I think the problem is with the parameters but im not sure, any thoughts?
#include <stdio.h>
void swap(char *x, char *y);
/* Function to swap values at two pointers */
void swap(char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
int main(int argc, const char * argv[]) {
// insert code here...
char *a = "ASD123";
swap (a+1 , a+2);
return 0;
}
You need to post the complete crash log to be sure, but it's probably that you are attempting to manipulate a string constant:
char *a = "ASD123";
swap (a+1 , a+2);
which probably lives in read-only memory.
Try:
char a[12];
strcpy(a, "ASD123");
swap (a+1 , a+2);
or:
char a[] = "ASD123";
swap (a+1 , a+2);
That will copy the string onto the stack, where it may be modified without issue. You could also use strdup() to copy the string onto the heap (don't forget to call free() to release the allocated memory).
You are trying to modify a string literal.
Change
char *a = "ASD123";
to
char a[] = "ASD123";
and your program will work.
In the first case a is simply a pointer pointing to a string literal which is in a write protected part of the memory on most platforms, hence the crash because you try to write info write protected memory.
In the second case a is a char array of length 7 which is initialized with "ASD123" (6 chars for the string and one char for the terminating zero).
You need to initialize a correctly. Something like char a[7] = "ASD123";
char* a only creates a pointer-to-char, it does not allocate enough memory to store the characters.

char* leads to segfault but char[] doesn't [duplicate]

This question already has answers here:
Difference between char[] and char * in C [duplicate]
(3 answers)
Closed 7 years ago.
I think I know the answer to my own question but I would like to have confirmation that I understand this perfectly.
I wrote a function that returns a string. I pass a char* as a parameter, and the function modifies the pointer.
It works fine and here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_file_name(char* file_name_out)
{
char file_name[12+1];
char dir_name[50+12+1];
strcpy(file_name, "name.xml");
strcpy(dir_name, "/home/user/foo/bar/");
strcat(dir_name, file_name);
strcpy(file_name_out, dir_name); // Clarity - equivalent to a return
}
int main()
{
char file_name[100];
get_file_name(file_name);
printf(file_name);
return 0;
}
But if I replace char file_name[100]; by char *filename; or char *filename = "";, I get a segmentation fault in strcpy().
I am not sure why ?
My function takes a char* as a parameter and so does strcpy().
As far as I understand, char *filename = ""; creates a read-only string. strcpy() is then trying to write into a read-only variable, which is not allowed so the error makes sense.
But what happens when I write char *filename; ? My guess is that enough space to fit a pointer to a char is allocated on the stack, so I could write only one single character where my file_name_out points. A call to strcpy() would try to write at least 2, hence the error.
It would explain why the following code compiles and yields the expected output:
void foo(char* a, char* b)
{
*a = *b;
}
int main()
{
char a = 'A', b = 'B';
printf("a = %c, b = %c\n", a, b);
foo(&a, &b);
printf("a = %c, b = %c\n", a, b);
return 0;
}
On the other hand, if I use char file_name[100];, I allocate enough room on the stack for 100 characters, so strcpy() can happily write into file_name_out.
Am I right ?
As far as I understand, char *filename = ""; creates a read-only
string. strcpy() is then trying to write into a read-only variable,
which is not allowed so the error makes sense.
Yes, that's right. It is inherently different from declaring a character array. Initializing a character pointer to a string literal makes it read-only; attempting to change the contents of the string leads to UB.
But what happens when I write char *filename; ? My guess is that
enough space to fit a pointer to a char is allocated on the stack, so
I could write only one single character into my file_name_out
variable.
You allocate enough space to store a pointer to a character, and that's it. You can't write to *filename, not even a single character, because you didn't allocate space to store the contents pointed to by *filename. If you want to change the contents pointed to by filename, first you must initialize it to point to somewhere valid.
I think the issue here is that
char string[100];
allocates memory to string - which you can access using string as pointer
but
char * string;
does not allocate any memory to string so you get a seg fault.
to get memory you could use
string = calloc(100,sizeo(char));
for example, but you would need to remember at the end to free the memory with
free(string);
or you could get a memory leak.
another memory allocation route is with malloc
So in summary
char string[100];
is equivalent to
char * string;
string = calloc(100,sizeo(char));
...
free(string);
although strictly speaking calloc initializes all elements to zero, whereas in the string[100] decalaration the array elements are undefined unless you use
string[100]={}
if you use malloc instead to grad the memory the contents are undefined.
Another point made by #PaulRooney is that char string[100] gives memory allocation on the stack whereas calloc uses the heap. For more information about the heap and stack see this question and answers...
char file_name[100]; creates a contiguous array of 100 chars. In this case file_name is a pointer of type (char*) which points to the first element in the array.
char* file_name; creates a pointer. However, it is not initialized to a particular memory address. Further, this expression does not allocate memory.
char *filename;
Allocate nothing. Its just a pointer pointing to an unspecified location (the value is whatever was in that memory previously). Using this pointer will never work as it probably points outside the memory range your program is allowed to use.
char *filename = "";
Points to a piece of the programs data segment. As you already said it's read only and so attempting to change it leads to the segfault.
In your final example you are dealing with single char values, not strings of char values and your function foo treats them as such. So there is no issue with the length of buffers the char* values point to.

C programming strcat using pointer

I am a beginner in C. I wanted to make strcat function using pointers. I made it but don't know what is wrong with it. I used gcc compiler and it gave segmentation fault output.
#include<stdio.h>
#include<string.h>
char scat(char *,char *);
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
while(*q!='\0') printf("the concatenated string is %c",*q);
}
char *scat(char *s,char *t)
{
char *p=s;
while(*p!='\0'){
p++;
}
while(*t!='\0'){
*p=*t;
p++;
t++;
}
return p-s-t;
}
This one works:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *scat(char *,char *); /* 1: your prototype was wrong */
void main()
{
char *s="james";
char *t="bond";
char *q=scat(s,t);
printf("cat: %s\n", q); /* 2: you can use %s to print a string */
free(q);
}
char *scat(char *s,char *t)
{
char *p=malloc(strlen(s)+strlen(t)+1); /* 3: you will have to reserve memory to hold the copy. */
int ptr =0, temp = 0; /* 4 initialise some helpers */
while(s[temp]!='\0'){ /* 5. use the temp to "walk" over string 1 */
p[ptr++] = s[temp++];
}
temp=0;
while(t[temp]!='\0'){ /* and string two */
p[ptr++]=t[temp++];
}
return p;
}
You have to allocate new space to copy at the end of s. Otherwise, your while loo[ will go in memory you don't have access to.
You shoul learn about malloc() here.
It is undefined behaviour to modify a string literal and s, and eventually p, is pointing to a string literal:
char* s = "james";
s is passed as first argument to scat() to which the local char* p is assigned and then:
*p=*t;
which on first invocation is attempting to overwite the null character an the end of the string literal "james".
A possible solution would be to use malloc() to allocate a buffer large enough to contain the concatentation of the two input strings:
char* result = malloc(strlen(s) + strlen(p) + 1); /* + 1 for null terminator. */
and copy them into it. The caller must remember to free() the returned char*.
You may find the list of frequently asked pointer questions useful.
Because p goes till the end of the string and then it starts advancing to illegal memory.
That is why you get segmentation fault.
It's because s points to "james\0", string literal & you cannot modify constant.
Change char *s="james"; to char s[50]="james";.
You need to understand the basics of pointers.
a char * is not a string or array of characters, it's the address of the beginning of the data.
you can't do a char * - char* !!
This is a good tutorial to start with
you will have to use malloc
You get a segmentation fault because you move the pointer to the end of s and then just start writing the data of p to the memory directly following s. What makes you believe there is writable memory available after s? Any attempt to write data to non-writable memory results in a segmentation fault and it looks like the memory following s is not writable (which is to expect, since "string constants" are usually stored in read-only memory).
Several things look out of order.
First keep in mind that when you want to return a pointer to something created within a function it needs to have been malloc'ed somewhere. Much easier if you pass the destination as an argument to the function. If you follow the former approach, don't forget to free() it when you're done with it.
Also, the function scat has to return a pointer in the declaration i.e. char *scat, not char scat.
Finally you don't need that loop to print the string, printf("%s", string); will take care of printing the string for you (provided it's terminated).
At first, your code will be in infinte loop because of the below line. you were supposed to use curely braces by including "p++; t++ " statements.
while(*t!='\0')
*p=*t;
though you do like this, you are trying to alter the content of the string literal. which will result in undefined behavior like segmentation fault.
A sequence of characters enclosed with in double quotes are called as string literal. it is also called as "string". String is fixed in size. once you created, you can't extend its size and alter the contents. Doing so will lead to undefined behavior.
To solve this problem , you need to allocate a new character array whose size is sum of the length of two strings passed. then append the two strings into the new array. finally return the address of the new array.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char* scat(char *,char *);
void append(char *t , char *s);
int main(void)
{
char *s="james";
char *t="bond";
char *n = scat(s,t);
printf("the concatenated string is %s",n);
return 0;
}
char* scat(char *s,char *t)
{
int len = strlen(s) + strlen(t);
char *tmp = (char *)malloc(sizeof(char)* len);
append(tmp,s);
append(tmp,t);
return tmp;
}
void append(char *t , char *s)
{
//move pointer t to end of the string it points.
while(*t != '\0'){
t++;
}
while( *s != '\0' ){
*t = *s;
t++;
s++;
}
}

Resources