Jus started learning about pointers and im stuck with this program outputting a segmentation fault.
Its supposed to copy the first 10 Characters of a string to the location pointed by the double pointer
using gdb ive found that **pt=*s; produces the seg fault
#include <stdio.h>
#include <stdlib.h>
void str1(char *s, char **pt);
void str1(char *s, char **pt){
for(int i=0;i<10;i++){
**pt=*s;
pt++;
s++;
}
}
int main (void) {
char str[30] = "223This is test";
char *ptr;
str1(str, &ptr);
printf("%s", ptr);
return 0;
}
First of all ptr is not initialized, you can't really use it until you reserve space for it or store a valid memory address in it, i.e. make it point to some valid variable.
char *ptr = malloc(11);
Then you need to increment it properly in the function:
(*pt)++;
Once the copy is completed you need to null terminate the char array so it can be treatead as a string, aka a null terminated char array.
**pt = '\0';
Now as ptr was passed as a pointer to pointer, the increment is known by the caller, main in this case, so when you try to print it, it prints nothing because it's pointing to the end of the char array, we need to bring it back to the beggining.
*pt -= 10;
Corrected code with comments taking yours as base:
Live demo
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
void str1(char *s, char **pt) {
for (int i = 0; i < SIZE; i++) {
**pt = *s;
(*pt)++; //properly increment pt
s++;
}
**pt = '\0'; //null terminate copied string
//since ptr was passed as **, the increment is known by the caller
//now ptr will be pointing to the end of the string
//we have to bring it back to the beginning
*pt -= SIZE;
}
int main(void) {
char str[] = "223This is test";
char *ptr = malloc(SIZE + 1); //space for 10 character + null-terminator
//check for allocation errors
if(ptr == NULL){
perror("malloc");
return EXIT_FAILURE;
}
str1(str, &ptr);
printf("%s", ptr);
free(ptr);
return EXIT_SUCCESS;
}
You probably want this:
#include <stdio.h>
#include <stdlib.h>
void str1(char* s, char** pt) {
char *p = malloc(100); // allocate memory for destination
*pt = p; // store it for the caller
for (int i = 0; i < 10; i++) {
*p = *s;
p++;
s++;
}
*p = 0; // put string terminator, otherwise printf won't work correctly
}
int main(void) {
char str[30] = "223This is test";
char *ptr; // for now p points nowhere
str1(str, &ptr); // now p points to the memory allocated in str1
printf("%s", ptr);
free(ptr); // free memory for completeness
return 0;
}
Related
So, I'm facing an issue that I don't really understand. Please be kind I'm trying to learn C by myself !
I have a function that is called secureInput() that takes a pointer to a string and a size so that, when the user has to type some input I can be sure that there is no buffer overflow. Now, the thing is that I want to modify the string without copying it so instead modifying it directly by it's memory address but it just crashes when the second character in user input is assigned. See comments to see where it crashes.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int secureInput(char **str, int size);
int main(int argc, const char * argv[]) {
char *mystring = NULL; // Declaring it a null so that I use malloc later
secureInput(&mystring, 10);
printf("%s\n", mystring);
}
int secureInput(char **str, int size)
{
*str = (char*)malloc(sizeof(char) *size); // Because **str is a null pointer, I use malloc to allocate memory.
if (*str == NULL)
return -1;
int c = 0;
unsigned int count = 0;
while((c = getchar()) != '\n' && count < size)
/* Here is where it crashes.
* But changing the bellow line as : *str[0][count++] = c;
* works as expected. Also, using a temporary pointer
* and later using it to replace *str, is also working
*/
*str[count++] = c;
*str[count] = '\0';
return 0;
}
So first off, you can pass a string as a char*, no need for char**. That is usually used for an array of strings when passed as argument. Then, if you want to use a fixed size array, a buffer, that has a constant, pre-defined size, don't use malloc. Dynamic memory allocation is always inefficient and risky, so only use it if absolutely necessary.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#define BUFFER_SIZE 10
int secureInput(char *str, int size);
int main(int argc, const char * argv[]) {
char mystring[BUFFER_SIZE]; // Declaring it a null so that I use malloc later
memset(mystring, 0, BUFFER_SIZE);
secureInput(mystring, BUFFER_SIZE);
printf("%s\n", mystring);
}
int secureInput(char *str, int size) {
char c = 0;
unsigned int count = 0;
c = getchar();
while(c != '\n' && count < size - 1) {
str[count++] = c;
c = getchar();
}
str[count] = '\0';
return 0;
}
EDIT:
I can see that there is still some confusion regarding the pointer arithmetic. Here is some address printing and a small figure, I hope it helps:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int secureInput(char **str, int size);
int main(int argc, const char * argv[]) {
char *mystring = NULL; // Declaring it a null so that I use malloc later
secureInput(&mystring, 10);
}
int secureInput(char **str, int size) {
*str = (char*)malloc(sizeof(char) *size); // Because **str is a null pointer, I use malloc to allocate memory.
(*str)[0] = 'a';
(*str)[1] = 'b';
(*str)[2] = 'c';
(*str)[3] = 0;
printf("address of the pointer that points to a pointer that points the first char of the array : %p\n", &str);
printf("value of the pointer that points to a pointer that points to the first char of the array : %p\n", str);
printf("address of the pointer that points to the first char of the array : %p\n", &(*str));
printf("value of the pointer that points to the first char of the array : %p\n", *str);
printf("address of the first char of the array: %p\n", &(**str));
printf("address of the seconds char of the array: %p\n", &((*str)[1]));
printf("value of the first char of the array : %c\n", **str);
printf("value of the second char of the array : %c\n", *(*str + 1));
printf("value of the second char of the array : %c\n", (*str)[1]);
printf("*str[1] is the same as *(str[1]), which runs to a segmentation fault\n");
return 0;
}
The output:
address of the pointer that points to a pointer that points the first char of the array : 0x7ffce24333f8
value of the pointer that points to a pointer that points to the first char of the array : 0x7ffce2433430
address of the pointer that points to the first char of the array : 0x7ffce2433430
value of the pointer that points to the first char of the array : 0x55a91985a2a0
address of the first char of the array: 0x55a91985a2a0
address of the seconds char of the array: 0x55a91985a2a1
value of the first char of the array : a
value of the second char of the array : b
value of the second char of the array : b
*str[1] is the same as *(str[1]), which runs to a segmentation fault
0x7ffce24333f8 0x7ffce2433430
+----------------+ +----------------+ +----------------+
| 0x7ffce2433430 | -------> | 0x55a91985a2a0 | -------> | a | 0x55a91985a2a0
+----------------+ +----------------+ +----------------+
+----------------+
| b | 0x55a91985a2a1
+----------------+
+----------------+
| c | 0x55a91985a2a2
+----------------+
The point is that it matters which pointer you dereference.
At least this problem:
Off by one
str[count] = '\0'; can write outside array bounds leading to OP''s trouble. Suggest count < size --> count + 1 < size.
Entire line not always read
Reading a partial line leads to trouble.
How about reading the entire line and report results? Let calling code provide the buffer as it is of fixed size.
Distinguish between reading an empty line and end-of-file.
Handle size == 0 gracefully.
// EOF: end-of-file with no input
// EOF: input error
// 0: input, but too much
// 1: Success
int secureInput(char *str, size_t size) {
if (str == NULL) {
size = 0;
}
bool too_many = false;
size_t count = 0;
int c;
while((c = getchar()) != '\n') {
if (c == EOF) {
if (feof(stdin) && count > 0) {
break;
}
if (size > 0) {
str[0] = '\0';
}
return EOF;
}
if (count + 1 < size) {
str[count++] = c;
} else {
too_many = true;
}
}
if (count < size) {
str[count] = '\0';
}
return count < size && !too_many;
}
This relates to C. I am having some trouble understanding how I can assign strings to char pointers within arrays from a function.
#include <stdio.h>
#include <string.h>
void function(char* array[]);
int main(void)
{
char* array[50];
function(array);
printf("array string 0: %s\n",array[0]);
printf("array string 1: %s\n",array[1]);
}
void function(char* array[])
{
char temp[] = "hello";
array[0] = temp;
array[1] = temp;
return;
}
Ideally, I would like the main printf function to return
array string 0: hello
array string 1: hello
But I'm having trouble understanding arrays of pointers, how these pass to functions and how to manipulate them in the function. If I declare a string like char temp[] = "string" then how do I assign this to one of the main function array[i] pointers? (assuming I have my jargon right)
char temp[] = "hello"; only creates a local, temporary array inside the function. So when the function exists, the array will be destroyed.
But with array[0] = temp; you're making array[0] point to the local array temp.
After the function returns, temp doesn't exist anymore. So accessing array[0] which pointed to temp will cause undefined behavior.
You could simply make temp static, so it also exists outside the function:
static char temp[] = "hello";
Or, you could copy the "hello" string to array[0] and array[1]. For copying C-strings, you normally use strcpy.
char temp[] = "hello";
strcpy(array[0], temp);
strcpy(array[1], temp);
However, before copying you need to make sure array[0] and array[1] point to memory that has enough space to hold all characters of "hello", including the terminating null character. So you have to do something like this before calling strcpy:
array[0] = malloc(6);
array[1] = malloc(6);
(6 is the minimum numbers of characters that can hold "hello".)
how do I assign this to one of the main function array[i] pointers
Arrays cannot be assigned.
A pointer cannot hold an array, it can only refer to an array. For the latter the pointer needs to get an array's address assigned.
Referring 1.
This
char temp[] = "hello";
isn't an assigment, but an initialisation.
This
char temp[];
temp[] = "hello";
would not compile (the 2nd line errors), as an array cannot be assigned.
Referring 2.
This
char* array[50];
defines an array of 50 pointers to char, it could reference 50 char-arrays, that is 50 C-"strings". It cannot hold the C-"strings" themselfs.
Example
Applying what is mentioned above to your code whould lead to for example the following:
#include <stdio.h>
#include <string.h>
void function(char* array[]);
int main(void)
{
char* array[50];
/* Make the 1st two elements point to valid memory. */
array[0] = malloc(42); /* Real code shall test the outcome of malloc()
as it might fail and very well return NULL! */
array[1] = malloc(42);
function(array);
printf("array string 0: %s\n",array[0]);
printf("array string 1: %s\n",array[1]);
return 0;
}
void function(char* array[])
{
char temp[] = "hello";
/* Copy the content of temp into the memory that was allocated to
the array's 1st memebrs in main(). */
strcpy(array[0], temp);
strcpy(array[1], temp);
return;
}
first, you need to allocate the destination.
second, char temp[] = "hello"; in function() is local variable. you cannot use their outside of the function. use strcpy to copy the content.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* dest)
{
char temp[] = "hello";
strcpy(dest, temp);
return;
}
int main(void)
{
// or just char dest[10] = {0};
char *dest = malloc(10);
function(dest);
printf("dest: %s\n", dest);
}
In you program, you defined char* array[50];, so you need to create memory space for each item:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void function(char* a[])
{
char temp[] = "hello";
strcpy(a[0], temp);
strcpy(a[1], temp);
return;
}
int main(void)
{
char *a[50];
int i = 0;
for (i = 0; i < 50; ++i)
a[i] = malloc(10);
function(a);
printf("a[0]: %s\n", a[0]);
printf("a[1]: %s\n", a[1]);
}
I have the following program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
char * decrypt(char *p, int key){
char *tmp;
for(int i = 0; p[i] != '\0'; i++){
tmp[i] = p[i]-key;
}
return tmp;
}
int main(void){
printf("Hallo Welt!");
printf("%s\n", decrypt("ibmmp", 1));
return EXIT_SUCCESS;
}
When I compile it with gcc -Wall i get the Warning tmp could get uninitialized in this function [-Wmaybe-uninitialized] tmp[i] = p[i]-key(translated from german) and segmentation fault (core dumped) ./crypto when i run it
What is causing that error?
I know this quesion has been asked many times, but i could not fix this warning, because other people had different sourcecodes and i couldn't adapt it to my problem.
You need to allocate 'tmp' and then, keeping with good 'c' coding, check that the allocation was successful. I assume you have MAX defined so you can set an upper-bound on the length of your string, so I use that below. If MAX is intended to be the number of characters without a null, then you need to 'malloc(MAX +1)'. If it is intended to include NULL, then just leave the code as defined below. You also want to decide what to return on failure of the malloc. I return NULL, but you may want to do something different depending on your needs.
Also be aware, that this function is returning allocated memory, so someone needs to free it so you aren't leaking memory.
char * decrypt(char *p, int key){
char *tmp;
tmp = (char *) malloc(MAX);
if(!tmp)
return NULL;
for(int i = 0; p[i] != '\0'; i++){
tmp[i] = p[i]-key;
}
return tmp;
}
Allocate memory for tmp before using it. Make sure you null-terminate the string before returning it.
// Make the input a const string.
// char * decrypt(char *p, int key){
char * decrypt(char const* p, int key){
char *tmp = malloc(strlen(p) + 1); // Allocate memory
int i = 0;
for( ; p[i] != '\0'; i++){
tmp[i] = p[i]-key;
}
tmp[i] = '\0'; // null terminate.
return tmp;
}
Make sure you deallocate the memory. Just using
printf("%s\n", decrypt("ibmmp", 1));
will result in a memory leak.
int main(void){
printf("Hallo Welt!");
char* dec = decrypt("ibmmp", 1)
printf("%s\n", dec);
free(dec); // Deallocate memory.
return EXIT_SUCCESS;
}
Here are the codes of a program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cloning(char * q){
char s[strlen(q)];
int i;
for(i = 0; i < strlen(q); i++)
s[i] = q[i];
return s;
}
int main(){
char q[] = "hello";
char *s = cloning(q);
return 0;
}
After the compilation a warning appears, so I changed the returned value like this:
char *b = s;
return b;
In this way the warning can be solved. However I found that inside the function cloning(), sizeof(s) is 5, but strlen(s) is 7. And if I change char s[strlen(q)] simply to char s[5], the output is still incorrect. Can anybody explain this problem to me? Thank you very much.
char s[strlen(q)] is a local variable, and hence when you return its address, it results in undefined behaviour. Thus either you could use strdup() or malloc() to dynamically allocate the array, thus ensuring that the array s is available on the heap when you return from the function. The returned array would need to be free()-ed as well, else it would have a memory leak :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * cloning(char * q){
char *s = malloc(strlen(q)+1);
// if you write char s[strlen(q)], it is defined locally, and thus on return gives an undefined behaviour
int i;
for(i = 0; i < strlen(q)+1; i++)
s[i] = q[i];
return s;
}
int main(){
char q[] = "hello";
char *s = cloning(q);
free(s);
return 0;
}
char s[strlen(q)];
is a variable-length array. Like a malloc'ed buffer its size is determined at runtime. Unlike a malloc'ed buffer, it ceases to exist when the function returns.
multiple issues with this code:
char * cloning(char * q){
char s[strlen(q)]; // s has strlen size but needs strlen + 1 to hold \0
int i;
for(i = 0; i < strlen(q); i++) // should copy the \0 otherwise q is not a valid string
s[i] = q[i];
return s;// returns the address of a local var == undef. behavior
}
if you want to clone a string just do strdup()
char* cloning(char* q)
{
return strdup(q);
}
or the equivalent
char * cloning(char * q)
{
char* s = malloc(strlen(q)+1);
int i;
for(i = 0; i < strlen(q)+1; i++)
s[i] = q[i];
return s;
}
The proper way to do this with standard C, no matter version of the C standard, is this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cloning (const char* str)
{
char* clone;
size_t size = strlen(str) + 1;
clone = malloc(size);
if(clone == NULL)
{
return NULL;
}
memcpy(clone, str, size);
return clone;
}
int main(){
char original[] = "hello";
char* clone = cloning(original);
if(clone == NULL)
{
puts("Heap allocation failed.");
return 0;
}
puts(clone);
free(clone);
return 0;
}
Dynamic arrays in C are declared using Malloc and Calloc. Try googling it.
Eg:
char *test;
test = (char *)malloc(sizeof(char)*Multiply_By);
In C,static array is in stack,after function return,it's been destoryed. and string with char has a '\0' end. But strlen don't include it. For example.char q[] = "hello"; strlen(q) = 5,but the real size is 6
If you want to copy a string, the last '\0' must be added at the end.or using
char *s = malloc(sizeof(q)); ...; for(i = 0; i < sizeof(q); i++)
s[i] = q[i];
you also need to free it after using.Maybe become a mem leak.
Hope this can help u.
I have a small piece of code. I compiled it with -lmcheck as I am trying to debug a code where I have the same similar error.
I get this error when I run this code:
memory clobbered before allocated block
Can someone explain the reason why free(ptr) will throw me this error?
How else can I free the pointer?
Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define LEN 5
int main(int argc, char *argv[]){
char *ptr = NULL;
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, ptr[i]);
ptr++;
}
free(ptr);
return 0;
}
You are incrementing ptr, therefore changing the address that it points to. You can't do that.
In your case, have a separate pointer, let's say char * p = ptr and do your operations with p leaving ptr intact so you can free(ptr) later.
EDIT Taking a second look at your code, I found that you are doing ptr++ when you shouldn't. You are accessing the characters in the array like ptr[i], if you mess with the ptr pointer, you are changing the base address and accessing the characters with ptr[i] can lead (and will lead) to unexpected results.
If you simply remove that line (ptr++) your code will magically work.
If you want to explore the pointer concept and try another solution, your code could look something like this:
int main(int argc, char *argv[]){
char *ptr = NULL;
char * p;
ptr = (char *) malloc(LEN+1);// +1 for string (please check for NULL)
p = ptr;
strcpy(ptr, "hello");
int i = 0;
while (*p) // note how I changed it to a while loop, C strings are NULL terminated, so this will break once we get to the end of the string. What we gain is that this will work for ANY string size.
{
printf("ptr[%d] = %c\n", i++, *p); // here i dereference the pointer, accessing its individual char
p++;
}
free(ptr);
return 0;
}
Because ptr no longer points to the base of the memory you allocated.
Also, after you increment ptr, the expression ptr[i] does not return what you might expect; and that is why the output starts with "hlo".
Find the answer in comments.
When you allocate some memory, typically, the memory management framework keep tracks of it by adding some more info (you can say Header and Footer) to the allocated memory area. When you free this memory, the same info is matched so as to detect any unwanted/invalid memory access.
int main(int argc, char *argv[]){
char *ptr = NULL;
char* temp = NULL; // Have a temp pointer.
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
temp = ptr; // manipulate temp pointer instead of ptr itself
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, temp[i]);
temp++; // Why you are incrementing this? Just to print, there is no need of this.
}
free(ptr);
return 0;
}