Array of pointers to char * in c using qsort - c

While adding string to my pointer's array, it is being overwriten by the last one. Could anyone tell me, where's my mistake?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (){
int ile = 3;
const char * slowa[ile];
for(int j = 0; j < ile; j++){
char string[30];
gets(string);
slowa[j] = string;
printf ("%s dodalem pierwsza\n",string);
}
for (int i = 0; i < ile; i++) {
printf ("%s numer %d\n",slowa[i],i);
}
return 0;
}

The answer is in the following two lines of code:
char string[30];
...
slowa[j] = string;
The assignment sets slowa[j] to the address of the same buffer, without making a copy. Hence, the last thing that you put in the buffer would be referenced by all elements of slowa[] array, up to position of j-1.
In order to fix this problem, make copies before storing values in slowa. You can use non-standard strdup, or use malloc+strcpy:
char string[30];
gets(string);
slowa[j] = malloc(strlen(string)+1);
strcpy(slowa[j], string);
In both cases you need to call free on all elements of slowa[] array to which you have assigned values in order to avoid memory leaks.

You're always pointing to array of chars which is stack variable it's locally allocated only in scope of function, possibly each declaration of string will be on the same address as previous iteration in your loop. You could either instead of using array of chars allocate memory each loop iteration or use array and then using i.e strdup allocate memory for your new string like
slowa[j] = strdup(string) :

As others have said, you need to create copies of the strings, otherwise you set the strings to the same address, and therefore they just overwrite each other.
Additionally, I think using fgets over gets is a much safer approach. This is because gets is very prone to buffer overflow, whereas with fgets, you can easily check for buffer overflow.
This is some code I wrote a while ago which is similar to what you are trying to achieve:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PTRS 3
#define STRLEN 30
int
string_cmp(const void *a, const void *b) {
const char *str1 = *(const char**)a;
const char *str2 = *(const char**)b;
return strcmp(str1, str2);
}
int
main(void) {
char *strings[PTRS];
char string[STRLEN];
int str;
size_t len, i = 0;
while (i < PTRS) {
printf("Enter a string: ");
if (fgets(string, STRLEN, stdin) == NULL) {
fprintf(stderr, "%s\n", "Error reading string");
exit(EXIT_FAILURE);
}
len = strlen(string);
if (string[len-1] == '\n') {
string[len-1] = '\0';
} else {
break;
}
strings[i] = malloc(strlen(string)+1);
if (strings[i] == NULL) {
fprintf(stderr, "%s\n", "Cannot malloc string");
exit(EXIT_FAILURE);
}
strcpy(strings[i], string);
i++;
}
qsort(strings, i, sizeof(*strings), string_cmp);
printf("\nSuccessfully read strings(in sorted order):\n");
for (str = 0; str < i; str++) {
printf("strings[%d] = %s\n", str, strings[str]);
free(strings[str]);
strings[str] = NULL;
}
return 0;
}

Related

Allocating memory for a string in C using malloc

I am trying to allocate memory for an array of strings using malloc. The size of each string is not known before the input from the user, so this is how I tried to allocate memory for each element in the array.
I have some errors with the code, but can't figure them out or can't understand them. I am getting an error regarding the allocation. Can anyone tell me what's wrong about this?
bool read_strings(char * strings[], int n)
{
int i = 0;
while (i<n)
{
char string[MAX_LENGTH];
if (scanf("%s", string)!=1)
return false;
char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
return false;
memory = string;
strings[i] = memory;
i++;
}
return true;
}
Thanks a lot!
At least you have to replace
char* memory= (char*)malloc(sizeof(char)*strlen(string));
if (memory == NULL)
return false;
memory = string;
strings[i] = memory;
by
strings[i] = strdup(string)
Note that using scanf("%s", string) the separator between the read string is the space
The problem is right here:
char* memory = (char*)malloc(sizeof(char)*strlen(string));
memory = string; <<<
strings[i] = memory;
You will lose memory if you assign strings to pointers like this.
Either:
a) Copy the string into the newly allocated memory using strcpy() or strncpy(), also make sure you have enough space for the NULL character \0
strings[i] = (char*)malloc(sizeof(char) * (strlen(string) + 1));
strcpy(strings[i], string);
b) Use strdup(), which is like a mix between strcpy() and malloc(), it creates just enough space for your string and copies it into a new memory location
strings[i] = strdup(string);
You have many mistakes
(char*)malloc(sizeof(char)*(strlen(string) **+ 1**)) . You have to reserve memory to '\0'
Very wrong
memory = string;
To copy strings you have to usr strcpy (the correct function nowadays is strncpy is more safe)
To have a truly unlimited buffer in C, (or limited by the amount of memory and a size_t,) you could build up the memory allocation incrementally.
#include <stdlib.h> /* realloc free */
#include <stdio.h> /* stdin fgets printf */
#include <string.h> /* strcpy */
#include <assert.h> /* assert */
#include <stdint.h> /* C99 SIZE_MAX */
#include <stdbool.h> /* C99 bool */
/* Returns an entire line or a null pointer, in which case eof or errno may be
set. If not-null, it must be freed. */
static char *line(void) {
char temp[1024] = "", *str = 0, *str_new;
size_t temp_len, str_len = 0;
while(fgets(temp, sizeof temp, stdin)) {
/* Count the chars in temp. */
temp_len = strlen(temp);
assert(temp_len > 0 && temp_len < sizeof temp);
/* Allocate bigger buffer. */
if(!(str_new = realloc(str, str_len + temp_len + 1)))
{ free(str); return 0; }
str = str_new;
/* Copy the chars into str. */
strcpy(str + str_len, temp);
assert(str_len < SIZE_MAX - temp_len); /* SIZE_MAX >= 65535 */
str_len += temp_len;
/* If on end of line. */
if(temp_len < sizeof temp - 1 || str[str_len - 1] == '\n') break;
}
return str;
}
static bool read_strings(char * strings[], int n) {
char *a;
int i = 0;
while(i < n) {
if(!(a = line())) return false;
strings[i++] = a;
}
return true;
}
int main(void) {
char *strings[4] = { 0 }; /* C99 */
size_t i;
bool success = false;
do {
if(!read_strings(strings, sizeof strings / sizeof *strings)) break;
for(i = 0; i < sizeof strings / sizeof *strings; i++)
printf("%lu: <%s>\n", (unsigned long)i, strings[i]);
success = true;
} while(0); {
for(i = 0; i < sizeof strings / sizeof *strings; i++)
free(strings[i]);
}
return success ? EXIT_SUCCESS : (perror("stdin"), EXIT_FAILURE);
}
I think that's right-ish. However, this should bring pause; what if they never hit enter? If one has a MAX_LENGTH, then consider allocating statically, depending on your situation.
Edit: It also has a worst-case running time that may not be desirable; if entering really arbitrarily large lines, use a geometric progression to allocate space.
I think this is what you wanted to do:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_strings(char * strings[], int n)
{
int i = 0;
char buffer[256] ={0}; /*a temp buffer of fixed max size for input */
if(NULL == strings)
{
return 0 ;
}
for (i= 0; i<n; ++i)
{
if (fgets(buffer, 256,stdin)== NULL) /*safer then scanf - read input into the buffer*/
return 0;
strings[i]= malloc(sizeof(char)*(strlen(buffer)+1)); /* the char poiner in he i place will now point to the newly allocated memory*/
strcpy(strings[i], buffer); /*copy the new string into the allocated memory now string[i] is pointing to a string*/
}
return 1;
}
static void printStringsArray(const char* strArr[], size_t size)
{
int i = 0;
if(NULL == strArr)
{
return;
}
for(i = 0; i< size; ++i)
{
printf("%s", strArr[i]);
}
}
int main(void)
{
char * arr[3]; /*array of (char*) each will point to a string after sending it to the function */
read_strings(arr,3);
printStringsArray(arr,3);
return 0;
}

How to copy an array of characters to a char pointer without using strcpy

How would I go about copying the characters of a char array into a char pointer without using strcpy aka manually. For example:
char *Strings[NUM];
char temp[LEN];
int i;
for (i = 0; i < NUM; i++){
fgets(temp, LEN, stdin);
Strings[i] = malloc(strlen(temp)+1);
Strings[i] = temp; // What would go here instead of this,
// because this causes this to happen->
}
Input:
Hello
Whats up?
Nothing
Output (when the strings in the array of char pointers are printed):
Nothing
Nothing
Nothing
I'm not sure how to fix this problem.
In your example, you use these two lines:
Strings[i] = malloc(strlen(temp)+1); /* you should check return of malloc() */
Strings[i] = temp;
Which is incorrect. The second line just overwrites the pointer given back from malloc(). You need to instead use strcpy() from <string.h>:
Strings[i] = malloc(strlen(temp)+1);
strcpy(Strings[i], temp);
char *strcpy(char *dest, const char *src) copies the string pointed to, from src to dest. dest is the destination, and src is the string to be copied. Returns a pointer to dest.
You are also not checking the return of fgets(), which returns NULL on failure. You should also consider removing the \n character appended by fgets(), as the strings you copy into Strings[i] will have a trailing newline, which might not be what you want.
Since another answer showed how to do it manually, you might want to also consider just using strdup() to do the copying for you.
strdup() returns a pointer to a new string which is duplicate of string str. Memory is obtained from malloc(), and deallocated from the heap with free().
Here is some example code which does extra error checking.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 3
#define BUFFSIZE 20
int main(void) {
char *strings[LEN] = {NULL};
char buffer[BUFFSIZE] = {'\0'};
size_t slen, strcnt = 0, i;
printf("Input:\n");
for (i = 0; i < LEN; i++) {
if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
fprintf(stderr, "Error from fgets()\n");
exit(EXIT_FAILURE);
}
slen = strlen(buffer);
if (slen > 0 && buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
fprintf(stderr, "Too many characters entered\n");
exit(EXIT_FAILURE);
}
if (*buffer) {
strings[strcnt] = strdup(buffer);
if (strings[strcnt] == NULL) {
fprintf(stderr, "Cannot allocate buffer\n");
exit(EXIT_FAILURE);
}
strcnt++;
}
}
printf("\nOutput:\n");
for (i = 0; i < strcnt; i++) {
printf("%s\n", strings[i]);
free(strings[i]);
strings[i] = NULL;
}
return 0;
}
So what is happening is you change the value of temp but all the pointers point to the one instance of temp. You need to allocate the memory and then copy over the array manually.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
int LEN = 20;
int NUM = 3;
char* Strings[NUM];
char temp[LEN];
int i,j;
for (i=0;i<NUM;i++){
fgets(temp,LEN,stdin);
Strings[i] = (char*)malloc(strlen(temp)+1);
for(j=0;j<=strlen(temp);j++) { /* this part */
if (j == strlen(temp))
Strings[i][j - 1] = temp[j]; /* overwrite \n with the terminating \0 */
else
Strings[i][j] = temp[j];
}
}
for (i=0;i<NUM;i++)
printf("%s\n", Strings[i]);
return 0;
}

Create variable numbers of string variables according to users's input(C language)

I would like to create an array of string variables, and the number of elements is depends on the user's input. For example, if the user's input is 3, then he can input 3 strings. Let's say "aaa", "bbb" and "ccc". They are stored by the same pointer to char(*ptr) but with different index.
code:
int main()
{
int t;
scanf("%d", &t);
getchar();
char *ptr = malloc(t*sizeof(char));
int i;
for(i=0;i<t;i++)
{
gets(*(ptr[i]));
}
for(i=0;i<t;i++)
{
puts(*(ptr[i]));
}
return 0;
}
t is the number of elements, *ptr is the pointer to array. I would like to store "aaa", "bbb" and "ccc" in ptr[0], ptr[1] and ptr[2]. However, errors have been found in gets and puts statement and i am not able to work out a solution. Would someone give a help to me? Thank you!
You shouldn't use gets(), which has unavoidable risk of buffer overrun, deprecated in C99 and deleted from C11.
Only one character can be stored in char. If the maximum length of strings to be inputted is fixed, you can allocate an array whose elements are arrays of char. Otherwise, you should use an array of char*.
Try this (this is for former case):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* the maximum length of strings to be read */
#define STRING_MAX 8
int main(void)
{
int t;
if (scanf("%d", &t) != 1)
{
fputs("read t error\n", stderr);
return 1;
}
getchar();
/* +2 for newline and terminating null-character */
char (*ptr)[STRING_MAX + 2] = malloc(t*sizeof(char[STRING_MAX + 2]));
if (ptr == NULL)
{
perror("malloc");
return 1;
}
int i;
for(i=0;i<t;i++)
{
if (fgets(ptr[i], sizeof(ptr[i]), stdin) == NULL)
{
fprintf(stderr, "read ptr[%d] error\n", i);
return 1;
}
/* remove newline character */
char *lf;
if ((lf = strchr(ptr[i], '\n')) != NULL) *lf = '\0';
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
free(ptr);
return 0;
}
You can use this code which is given below because string array is like char 2D array so use can use pointer of pointer and when you allocate memory at run time by malloc then you need to cast into pointer to pointer char type.
int main()
{
int t;
scanf("%d", &t);
char **ptr = (char **)malloc(t*sizeof(char));
int i,j;
for( i=0;i<t;i++)
{
scanf("%s",ptr[i]);
}
for(i=0;i<t;i++)
{
puts(ptr[i]);
}
return 0;
}
Here is an example, of a clean if slightly memory inefficient way to handle this. A more memory efficient solution would use one string of MAX_LINE_LENGTH and copy to strings of precise lengths.. which is why one contiguous block of memory for the strings is a bad idea.
The asserts also just demonstrate where real checks are needed as malloc is allowed to fail in production where asserts do nothing.
#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#define MAX_LINE_LENGTH 2048
int
main(void) {
int tot, i;
char **strheads; /* A pointer to the start of the char pointers */
if (scanf("%d\n", &tot) < 1)
return (1);
strheads = malloc(tot * sizeof (char *));
assert(strheads != NULL);
/* now we have our series of n pointers to chars,
but nowhere allocated to put the char strings themselves. */
for (i = 0; i < tot; i++) {
strheads[i] = malloc(sizeof (char *) * MAX_LINE_LENGTH);
assert(strheads[i] != NULL);
/* now we have a place to put the i'th string,
pointed to by pointer strheads[i] */
(void) fgets(strheads[i], MAX_LINE_LENGTH, stdin);
}
(void) printf("back at ya:\n");
for (i = 0; i < tot; i++) {
fputs(strheads[i], stdout);
free(strheads[i]); /* goodbye, i'th string */
}
free(strheads); /* goodbye, char pointers [0...tot] */
return (0);
}

Storing the buffer of fgets in Array

I'm new to C (coming from Java) and naturally that poses some difficulties. I would like to write just a short program that reads in char-Arrays from stdin and stores the individual strings in an array. After reading in the strings I just want to have them printed out, but that's when it gets really confusing for me.
Here's my code:
#include <stdlib.h>
#include <stdio.h>
int main(){
char **stringarray[2];
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
char *tmp = buffer;
stringarray[i] = &tmp;
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", &stringarray[i]);
}
return 0;
}
The first part does in fact compiles (i.e. the part before the print out). I understand that my stringArray has to be an array of char pointers, because that's what a char array basically is in c. It's a pointer to the first character. At first I just wrote
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = buffer;
i++;
}
which also compiled, but of course then I have one pointer that points to buffer, which will only save the last string that has been read.
What do I have to do that I can store a simple array of strings?
I suggest you change your code as following.
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* to use strdup function */
int main(){
char *stringarray[2]; /* I don't understand why you use pointer to pointer than pointer, char **stringarray[2]; */
char buffer[6]; /* I suggest 6 than 5, because string has terminate byte in C */
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL){
stringarray[i] = strndup(buffer, 5);
i++;
}
for(int i = 0; i < 2; i++){
printf("%s\n", stringarray[i]); /* changed stringarray */
}
return 0;
}
char **stringarray[2]; is like char ***stringarray because an array is like a pointer to the first value of the array.
printf wants a char* and &stringarray[i] is a char**
if a string is an array then an array of strings is an array of array.
So the code is :
int main()
{
char stringarray[2][5];//array of (array of char)
char buffer[5];
int i = 0;
while( i < 2 && fgets(buffer, 5, stdin) != NULL)
{
strcpy(stringarray[i],buffer); //copies the buffer into the string array
i++;
}
for(i = 0; i < 2; i++)
{
printf("%s\n", stringarray[i]);
}
return 0;
}
If you didn't want to use buffer you could just writte :
while( i < 2 && fgets(stringarray[i], 5, stdin) != NULL)
{
i++;
}
Note that you get 5 characters, the last one will be the NUL terminator \0. And because you have to press enter to validate, the one before \0 will be Line Feed\n. And you will only have 3 characters you really wanted.
You can do it using dynamic allocation technique as below .
#include<stdio.h>
#include<malloc.h>
#include <stdlib.h>
int main()
{
int num;
int len=0;
int i;
printf("Enter the number of elements to be entered ");
scanf("%d",&num);
//Allocate memory for the array of strings
char **var=(char **)malloc(num * sizeof(char *));
for(i=0;i<num;i++)
{
printf("Enter the string : ");
//get strings using getline
getline(&var[i],&len,stdin);
}
for(i=0;i<num;i++)
{
printf("String %d : %s \n",i,var[i]);
}
free(var);
}

Returning a string to a variable length character array

I have a program that reverses a string from an input of a variable length character array. The function returns a variable length character array and is printed. When I print the output, I do get the reversed string, but there are garbage characters appended to it in my console print.
Is this a "legal" operation in terms of returning to buffers? Can someone please critique my code and suggest a better alternative if it is not the right approach?
Thanks.
#include <stdio.h>
#include <stdlib.h>
char *reverse_string(char *input_string);
char *reverse_string(char *input_string)
{
int i=0;
int j=0;
char *return_string;
char filled_buffer[16];
while (input_string[i]!='\0')
i++;
while (i!=0)
{
filled_buffer[j]=input_string[i-1];
i--;
j++;
}
return_string=filled_buffer;
printf("%s", return_string);
return return_string;
}
int main (void)
{
char *returned_string;
returned_string=reverse_string("tasdflkj");
printf("%s", returned_string);
return 1;
}
This is my output from Xcode - jklfdsat\347\322̲\227\377\231\235
No, it isn't safe to return a pointer to a local string in a function. C won't stop you doing it (though sometimes the compiler will warn you if you ask it to; in this case, the local variable return_string prevents it giving the warning unless you change the code to return filled_buffer;). But it is not safe. Basically, the space gets reused by other functions, and so they merrily trample on what was once a neatly formatted string.
Can you explain this comment in more detail — "No, it isn't safe..."
The local variables (as opposed to string constants) go out of scope when the function returns. Returning a pointer to an out-of-scope variable is undefined behaviour, which is something to be avoided at all costs. When you invoke undefined behaviour, anything can happen — including the program appearing to work — and there are no grounds for complaint, even if the program reformats your hard drive. Further, it is not guaranteed that the same thing will happen on different machines, or even with different versions of the same compiler on your current machine.
Either pass the output buffer to the function, or have the function use malloc() to allocate memory which can be returned to and freed by the calling function.
Pass output buffer to function
#include <stdio.h>
#include <string.h>
int reverse_string(char *input_string, char *buffer, size_t bufsiz);
int reverse_string(char *input_string, char *buffer, size_t bufsiz)
{
size_t j = 0;
size_t i = strlen(input_string);
if (i >= bufsiz)
return -1;
buffer[i] = '\0';
while (i != 0)
{
buffer[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", buffer);
return 0;
}
int main (void)
{
char buffer[16];
if (reverse_string("tasdflkj", buffer, sizeof(buffer)) == 0)
printf("%s\n", buffer);
return 0;
}
Memory allocation
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *reverse_string(char *input_string);
char *reverse_string(char *input_string)
{
size_t j = 0;
size_t i = strlen(input_string) + 1;
char *string = malloc(i);
if (string != 0)
{
string[--i] = '\0';
while (i != 0)
{
string[j] = input_string[i-1];
i--;
j++;
}
printf("%s\n", string);
}
return string;
}
int main (void)
{
char *buffer = reverse_string("tasdflkj");
if (buffer != 0)
{
printf("%s\n", buffer);
free(buffer);
}
return 0;
}
Note that the sample code includes a newline at the end of each format string; it makes it easier to tell where the ends of the strings are.
This is an alternative main() which shows that the allocated memory returned is OK even after multiple calls to the reverse_string() function (which was modified to take a const char * instead of a plain char * argument, but was otherwise unchanged).
int main (void)
{
const char *strings[4] =
{
"tasdflkj",
"amanaplanacanalpanama",
"tajikistan",
"ablewasiereisawelba",
};
char *reverse[4];
for (int i = 0; i < 4; i++)
{
reverse[i] = reverse_string(strings[i]);
if (reverse[i] != 0)
printf("[%s] reversed [%s]\n", strings[i], reverse[i]);
}
for (int i = 0; i < 4; i++)
{
printf("Still valid: %s\n", reverse[i]);
free(reverse[i]);
}
return 0;
}
Also (as pwny pointed out in his answer before I added this note to mine), you need to make sure your string is null terminated. It still isn't safe to return a pointer to the local string, even though you might not immediately spot the problem with your sample code. This accounts for the garbage at the end of your output.
First, returning a pointer to a local like that isn't safe. The idiom is to receive a pointer to a large enough buffer as a parameter to the function and fill it with the result.
The garbage is probably because you're not null-terminating your result string. Make sure you append '\0' at the end.
EDIT: This is one way you could write your function using idiomatic C.
//buffer must be >= string_length + 1
void reverse_string(char *input_string, char* buffer, size_t string_length)
{
int i = string_length;
int j = 0;
while (i != 0)
{
buffer[j] = input_string[i-1];
i--;
j++;
}
buffer[j] = '\0'; //null-terminate the string
printf("%s", buffer);
}
Then, you call it somewhat like:
#define MAX_LENGTH 16
int main()
{
char* foo = "foo";
size_t length = strlen(foo);
char buffer[MAX_LENGTH];
if(length < MAX_LENGTH)
{
reverse_string(foo, buffer, length);
printf("%s", buffer);
}
else
{
printf("Error, string to reverse is too long");
}
}

Resources