Problems with arrays of pointers - c

I'm having an entry level C pointer problem... Let's say I have two strings and I want to print them. What am I misunderstanding in the code below?
void print_array(char **array[]) {
int i = 0;
while((*array)[i] != NULL) {
printf("%s\n", (*array)[i++]);
}
return;
}
int main(int argc, char** argv) {
char str1[] = "hello";
char str2[] = "world";
char **array = {str1, str2};
print_array(&array);
return (EXIT_SUCCESS);
}
For my code to work I need to access the array like it is in print_array

Another take on it (Much more refactoring).
Bugfixes:
Corrected confusion what should be dereferenced and how in print_array (Don't aspire to 3-star-programming, unless you must)
Added the missing sentinel-0 in to the array passed from main to print_array
Other changes:
Removed superfluous return-statements (main has an implicit return 0; at the end)
Removed superfluous checks for unequality to 0 / NULL
Removed one level of indirection from print_array
Use of const in print_array where appropriate
Eliminated counter-variable in print_array
Used a constant compound-literal in main (Needs C99)
#include <stdio.h>
void print_array(const char *const array[]) {
while(*array)
printf("%s\n", *array++);
}
int main() {
print_array((const char*[]){"hello", "world", 0});
}
See here on coliru
Undoing the cleanup steps changing the signature of print_array:
#include <stdio.h>
void print_array(char **array[]) {
for(char** p = *array; *p; p++)
printf("%s\n", *p);
}
int main() {
print_array(&(char**){(char*[]){"hello", "world", 0}});
}
Live on coliru

There's one too many *'s in print_array. It ought to be this:
void print_array(char *array[]) {
int i = 0;
while(array[i] != NULL) {
printf("%s\n", array[i++]);
}
}
That makes calling it straightforward. Change char **array to char *array[]. And don't forget to include a NULL entry at the end of the array.
int main(int argc, char** argv) {
char str1[] = "hello";
char str2[] = "world";
char *array[] = {str1, str2, NULL};
print_array(array);
return EXIT_SUCCESS;
}
On the other hand, if you're not supposed to modify print_array, then that's annoying. You'll need another variable to hold array's address temporarily.
char *array[] = {str1, str2, NULL};
char **p = array;
print_array(&p);
That's why I say there's one too many *'s in print_array.

since you're dealing with arrays, please pass in the number of array members to print_array. The code above is UB.
To fix your code:
void print_array(char *arr[], int cnt) {
int i = 0;
for(i = 0; i < cnt; i++) {
printf("%s\n", arr[i]);
}
return;
}
int main(int argc, char** argv) {
char str1[] = "hello";
char str2[] = "world";
char *arr[] = {str1, str2};
print_array(arr, 2);
return (0);
}

Another way:
#include <stdio.h>
void print_array(char *array[]) {
int i = 0;
while (array[i] != 0) {
printf("%s\n", array[i++]);
}
return;
}
int main(int argc, char** argv) {
char str1[] = "hello";
char str2[] = "world";
char *array[] = {str1, str2, 0};
print_array(array);
return 0;
}

Related

Unable to store string in a struct

This code is a part of a bigger program. I want to create an array of structs. The struct contains two data types: char and char*, each of which gets an input from the user. I'm a rookie and not able to find my way through this. Please help.
Error generated: Segmentation Fault 11.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char ch;
char str[20];
}typ;
typ* add(char* str, char ch);
int main(int argc, char const *argv[]){
typ* arr;
arr = (typ*)malloc(sizeof(typ));
char* name;
name = (char*)malloc(10);
*(name + 0)= 'c';
*(name + 1)= 'a';
*(name + 2)= 'p';
*(name + 3)= '\0';
char c = 'k';
arr = add(name, c);
printf("%c\n", arr->ch );
printf("%s\n", arr->str );
return 0;
}
typ* add(char* str, char ch){
typ tempo;
strcpy(str, tempo.str);
printf("%s\n", str);
tempo.ch = ch;
typ* temp;
*temp = tempo;
return temp;
}
You used arr for the allocated memory, but then you assign it to add's return value, the memory got lost at this point, you have a memory leak.
In the add function, you return a pointer to a variable with automatic storage, which does not exists after the function returns. That's why you are getting a segfault.
So I would allocate the struct in the add function, and returns it:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef struct {
char ch;
char str[20];
} Item;
Item* add(char* str, char ch);
int main(int argc, char const *argv[]){
int i;
int n = 3; // number of elements in the array
Item** arr = malloc(n * sizeof(Item*));
arr[0] = add("cap", 'k');
arr[1] = add("foo", 'i');
arr[2] = add("bar", 'j');
printf("%c\n", arr[0]->ch );
printf("%s\n", arr[0]->str );
for (i = 0; i < n; i++)
free(arr[i]);
free(arr);
return 0;
}
Item* add(char* str, char ch) {
Item *i = malloc(sizeof *i);
strcpy(i->str, str);
i->ch = ch;
return i;
}

How do I pass an array of character pointers as void *, then cast back to array of character pointers?

I'm passing an array of character pointers to sqlite3_exec, which takes 1 parameter and presents it as a void *, but then I want to access it as the array of character pointers in the callback function.
char *output_params[] = {"one", "two"};
result = sqlite3_exec(db, sql_statement, callback, output_params, &zErrMsg);
....
static int callback(void *param, int argc, char **argv, char **azColName) {
// How do I access my character array?
char *output_params[2] = (char **)param;
}
How do I access it after I pass it?
This works for me:
int callback(void *param, int argc, char **argv, char **azColName)
{
const char** p = (const char **)param;
printf("%s\n", p[0]);
printf("%s\n", p[1]);
}
Here's simple program that demonstrates the concept.
#include <stdio.h>
void foo(void* in)
{
char **p = (char**)in;
printf("%s\n", p[0]);
printf("%s\n", p[1]);
}
void main(int argc, char** argv)
{
char *output_params[] = {"one", "two"};
foo(output_params);
}

How to use qsort for an array of strings?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int sortstring(const void *str1, const void *str2) {
const char *rec1 = str1;
const char *rec2 = str2;
}
void sortutil(char* lines[]) {
qsort(lines, 200, sizeof(char), sortstring);
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "sortutil.h"
int getarray(char *lines[]) {
int i = 0;
char *text = (char *)malloc(200);
while (fgets(text, 200, stdin) != NULL) {
lines[i] = text;
i++;
text = (char *)malloc(200);
}
return i;
}
void printarray(char *lines[], int max) {
for (int i = 0; i < max; i++)
printf("%s\n\n", lines[i]);
}
int main(int argc, char* argv[]) {
char* arr[100];
int numlines = getarray(arr);
printf("There are %d lines\n", numlines);
printarray(arr, numlines);
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-s") == 0) {
sortutil(arr);
printarray(arr, numlines);
}
}
}
When I send in a file with arbitrary text, It'll read the file and print it out, but when i call -s and call the qsort function, it comes back with nulls. I'm sure I am using qsort incorrectly, what is the right way to use it for an array to char pointers?
Your comparator is being sent each pair by-address. I.e. they're pointer-to-pointer-to-char.
Change the comparator to:
int sortstring( const void *str1, const void *str2 )
{
char *const *pp1 = str1;
char *const *pp2 = str2;
return strcmp(*pp1, *pp2);
}
Likewise, your sortutil needs to know the number of items being sorted, as well as pass the correct size of each item. Change that to:
void sortutil(char* lines[], int count)
{
qsort(lines, count, sizeof(*lines), sortstring);
}
Finally, the call from main() should look like this:
sortutil(arr, numlines);
That should do it.
What the compar function gets are pointers to the elements in your array, which in this case, are pointers to char. So the parameters str1 and str2 are actually pointers to pointers to char. You must cast them like this:
int sortstring( const void *str1, const void *str2 )
{
const char *rec1 = *(char**)str1;
const char *rec2 = *(char**)str2;
int val = strcmp(rec1, rec2);
return val;
}
Then you have to use the proper element size in qsort.
qsort(lines, 200, sizeof(char*), sortstring);
This line is incorrect.
qsort(lines, 200, sizeof(char), sortstring);
Change it to
qsort(lines, 200, sizeof(char*), sortstring);

How to convert a character to string using a function that has character as argument and returns string?

I had problem while using a function to do the task.Do I need to pass a pointer to character as well to do the task.I used the following code
#include <stdio.h>
char* change(char c)
{
char s[2];
s[0]=c;
s[1]='\0';
return s;
}
int main()
{
char t='o';
char* kk;
kk=change(t);
printf("\n%s",kk);
return 0;
}
Thanks
You cannot return a pointer to a local variable from a function without making a copy. Two ways of doing what you need in C are
Asking the caller to provide a buffer for writing the string, and returning the length, and
Allocating the return value dynamically with malloc or an equivalent, and requiring the caller to free the resultant string.
Here is the first approach:
int change(char c, char* res, int len) {
if (len < 2) return -1; // Invalid parameters
res[0]=c;
res[1]='\0';
return 1;
}
Here is the second approach:
char* change(char c) {
char *res = malloc(2);
res[0]=c;
res[1]='\0';
return res;
}
#include <stdio.h>
#include <stdlib.h>
char* change1(char c){
static char s[2];
s[0]=c;
return s;
}
char* change2(char c){
char *s = malloc(2);
s[0]=c;
s[1]='\0';
return s;
}
char* change3(char c, char *s){
s[0]=c;
s[1]='\0';
return s;
}
int main() {
char t='o';
char* kk;
kk=change1(t);
printf("%s\n", kk);
kk=change2(t);
printf("%s\n", kk);
free(kk);
char s[2];
kk = change3(t, s);
printf("%s\n", kk);
return 0;
}
You can just change
char s[2];
to
char *s; s = malloc(2);
and your program should work fine.

C - Not getting the right value with an argument pointer

The get_current_path function gets a pointer to a char string of the current working directory. printf("%s\n", buf); in the function itself prints exactly what I want, but then outside of the function, printf("%s", thisbuf); gives me a lot of garbage. I assume I've made some silly mistake here, but I can't figure out what it is.
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
int get_current_path(char *buf) {
long cwd_size;
char *ptr;
cwd_size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *) malloc((size_t) cwd_size)) != NULL)
ptr = getcwd(buf, (size_t)cwd_size);
else cwd_size == -1;
printf("%s\n", buf);
printf("%ld\n", cwd_size);
return cwd_size;
}
int main (int argc, char **argv)
{
char *thisbuf;
get_current_path(thisbuf);
printf("%s", thisbuf);
return 0;
}
You should pass a pointer to char *
int get_current_path(char **buf)
{
*buf = ...;
}
int main()
{
char *thisbuf;
get_current_path(&thisbuf);
}
Parameters in C are pass-by-value, which means that get_current_path can't change the value of "thisbuf" passed in by the caller.
To make the change, you would have to pass in a pointer to "thisbuf":
int get_current_path(char **resultBuf) {
char *buf = (char *) malloc((size_t) cwd_size);
...
*resultBuf = buf; // changes "thisbuf" in the caller
}
....
get_current_path(&thisbuf); // note - passing pointer to "thisbuf"
Try this instead:
int get_current_path(char **buf) {
*buf = something; // Set buf with indirection now.
And:
int main (int argc, char **argv)
{
char *thisbuf;
get_current_path(&thisbuf);
printf("%s", thisbuf);
return 0;
}
You were trying to pass a copy of buf to get_current_path, so when buf was modified, the original pointer to buf was not modified.

Resources