C passing array of pointers - c

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]);
}

Related

Confused between passing strings to a function (C)

Why this works:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char st[] = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
And this doesn't:
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char*st = "Hello";
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
In first I initialized my string using:
char st[]="Hello"; (using array)
And in latter I used:
char*st="Hello"; (using pointer)
I'm kind of getting confused between these 2 initialization types, what's the key difference between declaring a string by using char st[]="Hello"; and by using char*st = "Hello";.
With char st[] = "Hello";, st[] is a modifiable array of characters. The call slice(st, 1, 6); takes the array st and converts to a pointer to the first element of the array. slice() then receives that pointer, a pointer to modifiable characters.
With char *st = "Hello";, st is a pointer that points to a string literal "Hello". With the call slice(st, 1, 6);, the function receives a copy of the pointer - a pointer to the string literal. Inside slice(), code st[i] = ... is attempting to modify a string literal, that is undefined behavior (UB). It might work, it might fail, it might work today and fail tomorrow - it is not defined.
Do not attempt to modify a string literal.
... passing strings to a function ...
In both cases, code does not pass a string to slice(), but a pointer to a string. Knowing that subtle distinction helps in understanding what is truly happening.
This is an artifact of old syntax in C:
char * s = "Hello world!";
is a non-const character pointer to const memory. It is still permitted by syntax, but the string is still not a mutable object. To be pedantic it should really be written as:
const char * s = "Hello world!";
In contrast:
char s[] = "Hello world!";
allocates a local (on the stack), mutable array and copies the string data to it (from wherever the non-mutable copy is stored in memory). Your function can then do as it likes to your local copy of the string.
The type char [] is different from the type char* (char* is a variable - int. but char[] is an array which is not a variable). However, an array name can be used as a pointer to the array.
So we can say that st[] is technically similar to *str .
the problem in the 2nd version of your code
If you have read-only strings then you can use const char* st = "hello"; or simply char* st = "hello"; . So the string is most probably be stored in a read-only memory location and you'll not be able to modify it.
However, if you want to be able to modify it, use the malloc function:
char *st= (char*) malloc(n*sizeof(char)); /* n-The initial size that you need */
// ...
free(st);
**So to allocate memory for st, count the characters ("hello"-strlen(st)=5) and add 1 for this terminating null character , and functions like scanf and strcpy will add the null character;
so the code becomes :
#include <stdio.h>
void slice(char *st, int m, int n)
{
int i = 0;
while ((i + m) < n)
{
st[i] = st[i + m];
i++;
}
st[i-1] = '\0';
}
int main()
{
char *st =malloc(6*sizeof(char)) ;
const char *cpy="hello";
strcpy(st, cpy); /* copies the string pointed by cpy (including the null character) to the st. */
slice(st, 1, 6);
printf("The value of string is %s\n", st);
return 0;
}
you can fill your string also by a for loop or by scanf() .
in the case of a large allocation you must end your code with free(st);

How to reverse every string in an array of strings through a function in C?

I have been trying to solve this issue for whole day, and could not do it on my own. Searching the internet didn't help me solve it either
So, this the function prototype:
void invert(char **arr, int n);
First argument is an array of strings, and the second one is number of strings in an array.
This is my code:
#include <stdio.h>
#include <string.h>
void invert(char** arr, int n)
{
int i, j, len;
for(j=0;j<n;j++)
{
len=strlen(arr[j]);
for(i=0;i<len/2;i++)
{
char tmp = arr[j][i];
arr[j][i] = arr[j][len - i - 1];
arr[j][len - i - 1] = tmp;
}
}
}
int main()
{
int n=3, i;
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
}
The code breaks when it reaches the line:
arr[j][i] = arr[j][len - i - 1];
and I can't figure out why.
The function receives an array of strings perfectly (tested it with some printf statements for characters of specific strings), and the char tmp succesfully recieves a correct character, but the program crashed when it reaches the line mentioned earlier. Printf statements after that line don't work.
Did I miss anything? Can someone explain what am I doing wrong? Thank you!
For starters this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
invokes undefined behavior because the pointer arr is uninitialized and has an indeterminate value.
Moreover this approach in any case is wrong because you may not change string literals.
What you need is to declare a two-dimensional array as for example
enum { N = 11 };
//...
char arr[3][N] =
{
"John", "Doe", "Programmer"
};
In this case the function declaration will look like
void invert( char arr[][N], int n );
The enumeration must be declared before the function declaration.
Instead of the two-dimensional array you could declare an array of pointers like
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
In this case the function declaration may be as shown in your question
void invert(char** arr, int n)
So what you need to do with minimal changes is to substitute this code snippet
char **arr;
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
for this code snippet
char s1[] = "John";
char s2[] = "Doe";
char s3[] = "Programmer";
char * arr[3] = { s1, s2, s3 };
To begin with, what you have here:
char **arr;
is a pointer to pointer to char.
Secondly, even if you had an array of pointers to char, like so :
char *arr[3];
And then assigning each string literal :
arr[0]="John";
arr[1]="Doe";
arr[2]="Programmer";
would still invoke Undefined behavior, since you are attempting to modify a string literal which is read only.
What you need is, either a 2D array of chars :
char arr[][100] = {"John", "Doe", "Programmer"};
and also change the function signature to :
void invert(char arr[][100], int n)
or you have to dynamically allocate memory and use a function like strcpy(), strdup(), memcpy() etc :
char **arr;
arr = malloc(n * sizeof(char *)); // or sizeof(*arr)
if (arr == NULL) {
fprintf(stderr, "Malloc failed to allocate memory\n");
exit(1);
}
arr[0] = strdup("John"); // good idea to also check if strdup returned null
arr[1] = strdup("Doe");
arr[2] = strdup("Programmer");
invert(arr, n);
for(i=0;i<3;i++)
{
printf("%s ",arr[i]);
}
for (i = 0; i < 3; i++) {
free(arr[i]);
}
free(arr);

Segmentation fault when trying to copy string with double pointer

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;
}

Why isn't this function(char*) pass by ref?

Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char* str){
str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
}
int main(){
char* s;
set(s);
printf("\n%s", s);
return 0;
}
Here's what I want to print out:
str = dog
dog
Here's what actuall gets printed out:
str = dog
(null)
Why is this? What I think I'm doing is passing an uninitalized pointer that then gets assigned a block of memory in set(), which then gets "dog" written into. What's actually going on?
There is no pass-by-reference in C. But pointers and indirection gives a facility to mimic that indirectly.
In your case, what is sent from main() to set() is the address in variable 's'. It
will have that value till malloc() statement executes. After that, str will have whatever address is returned by malloc().
When the same thing is expected in main, what should have been passed is the address
of 's' rather than what address it holds (like some of the examples above).
C is a pass-by-value language. There is no way to pass something by reference except explicitly. For your case that means expecting a pointer-to-a-pointer:
void set(char **str)
{
*str = malloc(10);
strcpy(*str, "dog");
printf("str = %s\n", *str);
}
And calling with the address of the pointer you want to 'fill in':
int main(void)
{
char *s;
set(&s);
printf("%s\n", s);
return 0;
}
Why isn't this function(char*) pass by ref?
C doesn’t have pass-by-reference. Everything is pass-by-value – it’s just that some values are also pointers to other values. Your uninitialized variable s is read when you call set(s) (which is undefined behaviour) in order to provide a value for its parameter str, then str = malloc(10) throws that value away to assign a new value to the local str.
You can pass a pointer to the pointer:
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
or return a pointer:
char* set(void) {
char* str = malloc(10);
strcpy(str, "dog");
printf("\nstr = %s", str);
return str;
}
int main(){
char* s = set();
printf("\n%s", s);
return 0;
}
You are passing an unasigned pointer to your set function, here a copy of the pointer is made and you use malloc on that copy. The original pointer in main is never updated with the new memory address.
To achieve what you want could be done this way:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void set(char** str){
*str = malloc(10);
strcpy(*str, "dog");
printf("\nstr = %s", *str);
}
int main(){
char* s;
set(&s);
printf("\n%s", s);
return 0;
}
I used a pointer to a pointer in set, and pass the memory address of the pointer s to it.

Printing a string character-by-character

int main() {
int i;
char a[]={"Hello"};
while(a!='\0') {
printf("%c",*a);
a++;
}
getch();
return 0;
}
Strings are stored in contiguous memory locations & while passing the address to printf() it should print the character. I have jst started learning C. I am not able to find an answer to this. Pls help.
Well a is the name of the array which you cannot increment. It is illegal to change the address of the array.
So define a pointer to a and then increment
#include <stdio.h>
#include <conio.h>
int main()
{
int i;
char a[]="Hello";
char *ptr = a;
while(*ptr!='\0')
{
printf("%c",*ptr);
// a++ here would be illegal
ptr++;
}
getch();
return 0;
}
NOTE:
In fact, arrays in C are non-modifiable lvalues. There are no
operations in C that can modify the array itself (only individual
elements can be modifiable).
In your code, a is a name of an array, you can't modify it like a++. Use a pointer like this:
char *p = "Hello";
while(*p++)
{
printf("%c",*p);
}
Three problems:
char a[]={"Hello"}; is illegal. {"Hello"} can only initialize char* a[]. You probably want char a[]="Hello";
while(a!='\0') - you probably meant *a != '\0'. a is the array itself.
a++; - an array cannot be incremented. you should increment a pointer pointing to it.
You can also try it using a for loop:
#include <stdio.h>
int main(void) {
char a[] = "Hello";
char *p;
for(p = a; *p != '\0'; p++) {
printf("%c", *p);
}
return 0;
}

Resources