Using scanf with array of pointers - c

char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
would this make pointers point to random place in memory or it's safe to use ?

char *username[30] is an array of pointers, not characters. So your code is very wrong (as in not safe). To get an array of characters you need:
char username[30];

char* username[30]; //is array of char pointers.
//Allocate memory for these pointers using calloc(). so no need of memset().
memset(username,0x00,30);//can be removed.
scanf("%s",&username);//It should be scanf("%s",username[i]);
#perreal, Sample added.
#define SIZE 100 //100 chars...
char* username[30];
int i;
for(i = 0; i < 30; i++)
{
username[i] = calloc(SIZE, sizeof(char)); //Add Fail checks if needed.
scanf("%s",username[i]);
}
so with the above code, you can get 30 strings. If you need only one string with 30 char then
char username[30];
memset(username,0x00,30);
scanf("%s",username);
is enough.

with
memset(username,0x00,30);
you are initializing the first 30 bytes of your array of pointers and not the whole array
memset(username,0, sizeof(username));
would set everything to 0 although a simple loop is clearer for the reader (IMHO)
for (int i = 0; i < 30; username[i++] = NULL) {;}
don't do this:
scanf("%s",&username);
scanf doesn't magically allocate anything -- "username" is an array of pointers and are NULL pointers, how should scanf know how to allocate memory etc? Instead do a loop, let user enter a string, allocate memory for that string (+1), copy the string to the allocated memory and assign it to "username[i]".

What you PROBABLY want is:
int i;
char* username[30];
for(i = 0; i < 30; i++)
{
username[i] = calloc(100, sizeof(char)); // or whatever size your string is.
scanf("%s",username[i]);
}
... Code using usernames ...
for(i = 0; i < 30; i++)
{
free(username[i]);
}
But personally, I'd probably go for:
int i;
char username[30][100];
for(i = 0; i < 30; i++)
{
scanf("%s",username[i]);
}
Saves on having to free the pointers later.
That will read 30 strings into your username array.
If you want to just read one username:
char username[30] = {0}; // Same as memset, but shorter to write!
scanf("%s", username);
Although as others have suggested, scanf() is't the best function to read "user generated input" - it's fine for data that your program has already "checked" (that is, it contains no "funny stuff", fits in the length provided, etc) and written to a file [using fscanf()]. For user input, use fgets() to read a line of text, and then work through it in whatever way is suitable to get the actual data out of the string.
For example, if some username has more than 100 characters [or thirty in the last example], the string will overflow, and nothing good will ever come from that [and in really bad cases, you won't notice until MUCH later, which makes it hard to debug - if you are lucky, it crashes immediately].

char* username[30];
memset(username,0x00,30);
scanf("%s",&username);
the above your code will get crash , because you are trying to input into pointer for which memory is not allocated. so first you allocate memory for the pointers and then you read into that memory location.

char *username[30]
This is an array of pointers to characters..
go for char username[30]

Related

comparing string to words in an array

I got an assignment from my teacher to write a code that compares a given word to a bunch of words located in an array of strings.
If the word in the array is lexicography smaller than the word given, I need to put it inside a new array.
else, I'm moving to the next word.
for example;
given word: hello
arr=bus, alpha, world, java.
new array=bus,alpha.
I wrote a code that does that using STRCMP, but the computer throws me out when it gets to the strcpy part.
this is my code
char** LowerSTR(char* arr[], int size_arr, char* str, int* size_res)
size_res = 0;
char** newArr= (char**)calloc(size_arr, sizeof(char));
for (int i = 0; i < size_arr; i++)
{
if (strcmp(str, arr[i])==1)
{
for (int k = 0; k <size_arr;k++)
{
strcpy(newArr[k], arr[i]);
}
size_res++;
}
}
if (size_res == 0)
return NULL;
else return newArr;}
maybe I should use STRCAT instead?
please help :\
In calling strcpy with newArr[k] as an argument you're dereferencing a NULL pointer.
Recall that we allocate newArr as follows:
char** newArr= (char**)calloc(size_arr, sizeof(char));
There's actually multiple errors here. The first is that we calloc with sizeof(char) when we in fact want a region of char*s. So corrected1
we have
char** newArr= calloc(size_arr, sizeof(char*));
As we've calloc'd this piece of memory, all of it is zeroed. Thus when strcpy internally accesses newArr[k] (itself of type char*) it points to memory address 0, which is likely reversed by the OS, and in any case, not a valid address in the context of our program.
In order to resolve this, we need to allocate for each string. For instance, one might do
newArr[k] = malloc(strlen(arr[i]) + 1); // The +1 is for the \0 termination character
the line before we strcpy.
You also have a bug with size_res as you just treat it as an int instead of an int* as you need to dereference it when you want to change or read the value to which it points.
1 See here for why I've removed the cast.
You should scan newArr and print all strings inside, something like:
for (int i = 0; i < *size_res; i++) // !
{
printf("%s\n",newArr[i]);
}
(!) 'size_res' is passed to the function as a pointer to int,

Reading array of string in C

I need to read an array of n strings from 2 letters in each (e.g. n = 3, need to read something near "ab bf cs"). I use this code and get segmentation fault:
int n;
scanf("%d", &n);
char array[n][2];
char *tmp;
for (int i = 0; i < n; i++)
{
scanf("%s", &tmp);
strcpy(array[i], tmp);
}
Please help me to fix it!
Problem 1
To store a string of length 2, you need a char array of size 3. Use:
char array[n][3];
Problem 2
You are using &tmp in the call to scanf. That is wrong on two accounts.
The type is not appropriate. Type of &tmp is char**. scanf needs a char* with the %s format specifier.
&tmp cannot hold a string.
You could use
scanf("%s", tmp);
That will be OK from type point of view but it won't ok from run time point of view since tmp does not point to anything valid.
You can do away with tmp altogether and use:
scanf("%s", array[i]);
That entire block of code can be:
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
// Make sure you don't read more than 2 chars.
scanf("%2s", array[i]);
}
There are a couple things you need to fix here.
Remember that one "string" (char[]) always ends with a null terminating character \0. So, whenever you create a char[], you must leave enough space for that. For example:
char str[3] = "foo"; looks like ['f', 'o', 'o'], but
char str[4] = "foo"; looks like ['f', 'o', 'o', '\0'].
Unexpected consequences can occur when using the former.
This means that you should change char array[n][2] to char array[n][3].
Remember that pointers are different than arrays. If you want to use a pointer, you must allocate memory for it, otherwise you will most likely seg fault.
In your program, it's simple enough that you can probably get away with not using a pointer, especially since you know the the length of each string that you will be storing (2).
You could change char *tmp to char tmp[3].
You can actually refactor your code so you don't need the tmp variable at all. If you want, you can just store the word you read into the array directly. For example:
scanf("%s", array[n]);
If you are really insistent on using that tmp variable as a char *, then allocate memory for it, like so:
char *tmp = (char*)malloc(3 * sizeof(char));
As a sidenote, if you are adhering to the ISO C90 standards, you shouldn't intermix variable declarations in code, so in your loop where you have for(int i = 0...), you should declare int i; at the top of the file, and then assign it in the loop for(i = 0...).
First, as user3121023 pointed out in the comments, char *tmp; creates a pointer without memory allocated to it. scanf() needs an array, and you need space for the terminating '\0' (which is probably the source of your segmentation fault). So you could try scanf("%s", array[i]);.
Second, it's a good idea to use "%2s" instead of "%s" so the user doesn't input 3 digits and overflow your buffer.
Here's one solution.
int n;
scanf("%d", &n);
char array[n][3];
for (int i = 0; i < n; i++)
{
scanf("%2s", array[i]);
}

Using Malloc for i endless C -String

I was wondering is it possible to create one endless array which can store endlessly long strings?
So what I exactly mean is, I want to create a function which gets i Strings with n length.I want to input infinite strings in the program which can be infinite characters long!
void endless(int i){
//store user input on char array i times
}
To achieve that I need malloc, which I would normally use like this:
string = malloc(sizeof(char));
But how would that work for lets say 5 or 10 arrays or even a endless stream of arrays? Or is this not possible?
Edit:
I do know memory is not endless, what I mean is if it where infinite how would you try to achieve it? Or maybe just allocate memory until all memory is used?
Edit 2:
So I played around a little and this came out:
void endless (char* array[], int numbersOfArrays){
int j;
//allocate memory
for (j = 0; j < numbersOfArrays; j++){
array[j] = (char *) malloc(1024*1024*1024);
}
//scan strings
for (j = 0; j < numbersOfArrays; j++){
scanf("%s",array[j]);
array[j] = realloc(array[j],strlen(array[j]+1));
}
//print stringd
for (j = 0; j < numbersOfArrays; j++){
printf("%s\n",array[j]);
}
}
However this isn't working maybe I got the realloc part terrible wrong?
The memory is not infinite, thus you cannot.
I mean the physical memory in a computer has its limits.
malloc() will fail and allocate no memory when your program requestes too much memory:
If the function failed to allocate the requested block of memory, a null pointer is returned.
Assuming that memory is infinite, then I would create an SxN 2D array, where S is the number of strings and N the longest length of the strings you got, but obviously there are many ways to do this! ;)
Another way would be to have a simple linked list (I have one in List (C) if you need one), where every node would have a char pointer and that pointer would eventually host a string.
You can define a max length you will assume it will be the max lenght of your strings. Otherwise, you could allocate a huge 1d char array which you hole the new string, use strlen() to find the actual length of the string, and then allocate dynamically an array that would exactly the size that is needed, equal of that length + 1 for the null-string-terminator.
Here is a toy example program that asks the user to enter some strings. Memory is allocated for the strings in the get_string() function, then pointers to the strings are added to an array in the add_string() function, which also allocates memory for array storage. You can add as many strings of arbitrary length as you want, until your computer runs out of memory, at which point you will probably segfault because there are no checks on whether the memory allocations are successful. But that would take an awful lot of typing.
I guess the important point here is that there are two allocation steps: one for the strings and one for the array that stores the pointers to the strings. If you add a string literal to the storage array, you don't need to allocate for it. But if you add a string that is unknown at compile time (like user input), then you have to dynamically allocate memory for it.
Edit:
If anyone tried to run the original code listed below, they might have encountered some bizarre behavior for long strings. Specifically, they could be truncated and terminated with a mystery character. This was a result of the fact that the original code did not handle the input of an empty line properly. I did test it for a very long string, and it seemed to work. I think that I just got "lucky." Also, there was a tiny (1 byte) memory leak. It turned out that I forgot to free the memory pointed to from newstring, which held a single '\0' character upon exit. Thanks, Valgrind!
This all could have been avoided from the start if I had passed a NULL back from the get_string() function instead of an empty string to indicate an empty line of input. Lesson learned? The source code below has been fixed, NULL now indicates an empty line of input, and all is well.
#include <stdio.h>
#include <stdlib.h>
char * get_string(void);
char ** add_string(char *str, char **arr, int num_strings);
int main(void)
{
char *newstring;
char **string_storage;
int i, num = 0;
string_storage = NULL;
puts("Enter some strings (empty line to quit):");
while ((newstring = get_string()) != NULL) {
string_storage = add_string(newstring, string_storage, num);
++num;
}
puts("You entered:");
for (i = 0; i < num; i++)
puts(string_storage[i]);
/* Free allocated memory */
for (i = 0; i < num; i++)
free(string_storage[i]);
free(string_storage);
return 0;
}
char * get_string(void)
{
char ch;
int num = 0;
char *newstring;
newstring = NULL;
while ((ch = getchar()) != '\n') {
++num;
newstring = realloc(newstring, (num + 1) * sizeof(char));
newstring[num - 1] = ch;
}
if (num > 0)
newstring[num] = '\0';
return newstring;
}
char ** add_string(char *str, char **arr, int num_strings)
{
++num_strings;
arr = realloc(arr, num_strings * (sizeof(char *)));
arr[num_strings - 1] = str;
return arr;
}
I was wondering is it possible to create one endless array which can store endlessly long strings?
The memory can't be infinite. So, the answer is NO. Even if you have every large memory, you will need a processor that could address that huge memory space. There is a limit on amount of dynamic memory that can be allocated by malloc and the amount of static memory(allocated at compile time) that can be allocated. malloc function call will return a NULL if there is no suitable memory block requested by you in the heap memory.
Assuming that you have very large memory space available to you relative to space required by your input strings and you will never run out of memory. You can store your input strings using 2 dimensional array.
C does not really have multi-dimensional arrays, but there are several ways to simulate them. You can use a (dynamically allocated) array of pointers to (dynamically allocated) arrays. This is used mostly when the array bounds are not known until runtime. OR
You can also allocate a global two dimensional array of sufficient length and width. The static allocation for storing random size input strings is not a good idea. Most of the memory space will be unused.
Also, C programming language doesn't have string data type. You can simulate a string using a null terminated array of characters. So, to dynamically allocate a character array in C, we should use malloc like shown below:
char *cstr = malloc((MAX_CHARACTERS + 1)*sizeof(char));
Here, MAX_CHARACTERS represents the maximum number of characters that can be stored in your cstr array. The +1 is added to allocate a space for null character if MAX_CHARACTERS are stored in your string.

Allocate memory to array of strings in C

I know this question (or similar) was asked many times, but I was still struggling to find a good answer, so please don't mark it as duplicate. I am trying to allocate memory for two arrays of strings. The strings are 500 and 1000 chars long, and the number of strings is known at the runtime. Here is my code:
char *arrOfPrompts = (char*)calloc(500*maxR, sizeof(char));
char *arrOfPhonePrompts = (char*)calloc(1000*maxR, sizeof(char));
char **prompts = (char**)calloc(maxR, sizeof(char*));
char **phonePrompts = (char**)calloc(maxR,sizeof(char*));
for (int i = 0; i<maxR; i++)
{
prompts[i] = arrOfPrompts+(i*500);
phonePrompts[i] = arrOfPhonePrompts+(i*1000);
(prompts[i])[i*500] = '\0';
(phonePrompts[i])[i*500] = '\0';
}
..where maxR is number of the arrays. So what I am doing is creating a long char array and then storing strings at 500 offsets. Is this a legit way of doing it? Looks ugly. Also, the reason I put '\0' character at the beginning of every "string" is because I then want to append to it using strcat. Are there any potential problems with this?
Thanks.
The following lines are not right. They will end up modifying memory beyond what you have allocated.
(prompts[i])[i*500] = '\0';
(phonePrompts[i])[i*500] = '\0';
Let's say maxR is 10.
arrOfPrompts points to an array of 5000 characters.
In the for loop, you use:
prompts[i] = arrOfPrompts+(i*500);
That means prompts[9] points to memory starting at the 4501-th character.
prompt[i][i*500] is prompt[9][4500] for i = 9. That will end up accessing a character that is 4000 elements away from the memory you allocated.
Since you are using calloc to allocate memory, you don't need to do anything more to create empty strings.
If you want to do it anyway, you can use:
prompts[i][0] = '\0';
phonePrompts[i][0] = '\0';
Your code seems fine but it may give unexpected results sometimes.
Another method to allocate 2D array of chars is:-
//r=number of rows
//c=number of columns
char **arr = (char **)malloc(r * sizeof(char *));
for (i=0; i<r; i++)
arr[i] = (char *)malloc(c * sizeof(char));

Allocating an array of an unknown size

Context: I'm trying to do is to make a program which would take text as input and store it in a character array. Then I would print each element of the array as a decimal. E.g. "Hello World" would be converted to 72, 101, etc.. I would use this as a quick ASCII2DEC converter. I know there are online converters but I'm trying to make this one on my own.
Problem: how can I allocate an array whose size is unknown at compile-time and make it the exact same size as the text I enter? So when I enter "Hello World" it would dynamically make an array with the exact size required to store just "Hello World". I have searched the web but couldn't find anything that I could make use of.
I see that you're using C. You could do something like this:
#define INC_SIZE 10
char *buf = (char*) malloc(INC_SIZE),*temp;
int size = INC_SIZE,len = 0;
char c;
while ((c = getchar()) != '\n') { // I assume you want to read a line of input
if (len == size) {
size += INC_SIZE;
temp = (char*) realloc(buf,size);
if (temp == NULL) {
// not enough memory probably, handle it yourself
}
buf = temp;
}
buf[len++] = c;
}
// done, note that the character array has no '\0' terminator and the length is represented by `len` variable
Typically, on environments like a PC where there are no great memory constraints, I would just dynamically allocate, (language-dependent) an array/string/whatever of, say, 64K and keep an index/pointer/whatever to the current end point plus one - ie. the next index/location to place any new data.
if you use cpp language, you can use the string to store the input characters,and access the character by operator[] , like the following codes:
std::string input;
cin >> input;
I'm going to guess you mean C, as that's one of the commonest compiled languages where you would have this problem.
Variables that you declare in a function are stored on the stack. This is nice and efficient, gets cleaned up when your function exits, etc. The only problem is that the size of the stack slot for each function is fixed and cannot change while the function is running.
The second place you can allocate memory is the heap. This is a free-for-all that you can allocate and deallocate memory from at runtime. You allocate with malloc(), and when finished, you call free() on it (this is important to avoid memory leaks).
With heap allocations you must know the size at allocation time, but it's better than having it stored in fixed stack space that you cannot grow if needed.
This is a simple and stupid function to decode a string to its ASCII codes using a dynamically-allocated buffer:
char* str_to_ascii_codes(char* str)
{
size_t i;
size_t str_length = strlen(str);
char* ascii_codes = malloc(str_length*4+1);
for(i = 0; i<str_length; i++)
snprintf(ascii_codes+i*4, 5, "%03d ", str[i]);
return ascii_codes;
}
Edit: You mentioned in a comment wanting to get the buffer just right. I cut corners with the above example by making each entry in the string a known length, and not trimming the result's extra space character. This is a smarter version that fixes both of those issues:
char* str_to_ascii_codes(char* str)
{
size_t i;
int written;
size_t str_length = strlen(str), ascii_codes_length = 0;
char* ascii_codes = malloc(str_length*4+1);
for(i = 0; i<str_length; i++)
{
snprintf(ascii_codes+ascii_codes_length, 5, "%d %n", str[i], &written);
ascii_codes_length = ascii_codes_length + written;
}
/* This is intentionally one byte short, to trim the trailing space char */
ascii_codes = realloc(ascii_codes, ascii_codes_length);
/* Add new end-of-string marker */
ascii_codes[ascii_codes_length-1] = '\0';
return ascii_codes;
}

Resources