Assigning value to pointer correctly in C using strcpy() - arrays

I need to take only the odd values from a char array and copy them into correctly sized dynamic memory using a pointer.
However when running my program it works correctly with certain input strings and not with others. Is there something that I'm doing wrong? I can't seem to figure out what's going on.
/* A.) Include the necessary headers in our program */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_LENGTH 32
int main() {
/* B.) Declare char array with inital size of 32 */
char input_string[MAX_STRING_LENGTH];
/* C.) Recieve user input.
Can save the first 31 characters in the array with 32nd reserved for '\0' */
printf("Enter a string of characters: ");
/* D.) Using the technique we discussed to limit the string to 31 charaters */
scanf("%31s", input_string);
printf("\n");
/* Will be used to determine the exact amount of dynamic memory that will be allocated later */
int odd_value_count = 0;
printf("Odd Characters: ");
for(int i = 0; i < strlen(input_string); i++) {
if(i % 2 != 0) {
printf("%c ", input_string[i]);
odd_value_count++;
}
}
printf("\n");
printf("Odd value count: %d\n", odd_value_count);
/* E.) Delecaring the pointer that will hold some part of the input_string
Pointer will be a char type */
char *string_pointer;
/* G.) Allocating the space before the copy using our odd value count */
/* H.) The exact amount of space needed is the sizeof(char) * the odd value count + 1 */
string_pointer = (char *)malloc(sizeof(char) * (odd_value_count + 1));
if (string_pointer == NULL) {
printf("Error! Did not allocte memory on heap.");
exit(0);
}
/* F.) Copying all charcters that are on the odd index of the input_string[] array
to the memory space pointed by the pointer we delcared */
printf("COPIED: ");
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
printf("%c ", input_string[i]);
}
}
/* Printing out the string uses the pointer, however we must subtract odd_value_count to
position the pointer back at the original start address */
printf("\n%s\n", string_pointer - odd_value_count);
return 0;
}
This input string: 01030507
works fine and copies & prints: 1357
The input string: testing
Copies etn but prints etng.
I cant figure out why for some strings it prints out the extra character at the end when I never even copy the value over.

You need to Null Terminate your string, like this *string_pointer = '\0';, just after you are done copying the odd characters in your string pointer - after that loop, null terminate your string.
Read more in How to add null terminator to char pointer, when using strcpy?

In the end of your routine you will need to null terminate the string, otherwise you don't have a string you just have a char array, you can use string_pointer which is already pointing to one past the end of the string you want to save:
//...
for (int i = 0; i < strlen(input_string); ++i) {
if(i % 2 != 0) {
strcpy(string_pointer++, &input_string[i]);
//as you are copying characters, you can do this:
//*string_pointer++ = input_string[i];
//instead of strcpy
printf("%c ", input_string[i]);
}
}
*string_pointer = '\0'; // <-- here
//...

Related

How to return empty string from a function in C?

How should I return an empty string from a function? I tried using lcp[i] = ' ' but it creates an error. Then I used lcp[i] = 0 and it returned an empty string. However, I do not know if it's right.
Also, is it necessary to use free(lcp) in the caller function? Since I could not free and return at the same time.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 50
char *find_LCP(char str1[], char str2[]);
char *find_LCP(char str1[], char str2[]){
char * lcp = malloc(MAX_LEN * sizeof(char));
int a = strlen(str1);
int b = strlen(str2);
int min = a < b ? a : b;
for(int i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
lcp[i] = 0;
}
return lcp;
}
int main()
{
char str1[MAX_LEN], str2[MAX_LEN];
char * lcp;
printf("Enter first word > ");
scanf("%s", str1);
printf("Enter second word > ");
scanf("%s", str2);
lcp = find_LCP(str1, str2);
printf("\nLongest common prefix: '%s'\n", lcp);
free(lcp);
return 0;
}
An "empty" string is just a string with the first byte zero, so you can write:
s[0] = 0;
However, it is not clear what you are trying to do. The LCP of "foo" and "fob" is "fo", not the empty string.
You can also return as soon as you find the first non-matching character, no need to go until the end.
Further, you can simply pass the output string as a parameter and have lcp be an array. That way you avoid both malloc and free:
char lcp[MAX_LEN];
...
find_LCP(lcp, str1, str2);
If you want to empty a string without using a for loop then you can do
lcp[0] = 0
but for emptying a string it was right the way you did using a for loop.
There are plenty other ways of emptying the string word by word using for loop:
lcp[i] = '\0';
and it's the right way to make string empty as letter by letter you trying to do using for loop
But if you are not using some loops and simply empty a string then you can do this.
memset(buffer,0,strlen(buffer));
but this will only work for zeroing up to the first NULL character.
If the string is a static array, you can use:
memset(buffer,0,sizeof(buffer));
Your program has a bug: If you supply two identical strings, lcp[i] = 0; never executes which means that your function will return a string which is not NUL-terminated. This will cause undefined behvaior when you use that string in your printf in main.
The fix for this is easy, NUL-terminate the string after the loop:
int i;
for (i = 0; i < min; i++){
if(str1[i] == str2[i])
lcp[i] = str1[i];
else
break;
}
lcp[i] = 0;
As for the answer to the question, an empty string is one which has the NUL-terminator right at the start. We've already handled that as we've NUL-terminated the string outside the loop.
Also, is it necessary to use free(lcp) in the caller function?
In this case, it is not required as the allocated memory will get freed when the program exits, but I'd recommend keeping it because it is good practice.
As the comments say, you can use calloc instead of malloc which fills the allocated memory with zeros so you don't have to worry about NUL-terminating.
In the spirit of code golf. No need to calculate string lengths. Pick any string and iterate through it until the current character either null or differs from the corresponding character in the other string. Store the index, then copy appropriate number of bytes.
char *getlcp(const char *s1, const char *s2) {
int i = 0;
while (s1[i] == s2[i] && s1[i] != '\0') ++i;
char *lcp = calloc((i + 1), sizeof(*lcp));
memcpy(lcp, s1, i);
return lcp;
}
P.S. If you don't care about preserving one of input strings then you can simplify the code even further and just return the index (the position of the last character of the common prefix) from the function, then put '\0' at that index into one of the strings.

How to read strings from stdin into a two-dimensional array in c programming using scanf() and while loop?

I'm writing a c code to read strings from stdin with scanf() and while loop (into a two-dimensional char array). My strategy is to use an input array to temporarily store each string and then assign it to a preword array (fixed sized). However, my strategy failed and all strings stored in my arrays are the same (the last string input). How to fix it?
I used a fgets() and it works find. However, I cannot use it to deal with a new line of strings (from stdin). My fgets() reads only the first line and that's why I turn to scanf and while loop.
#include<stdio.h>
#include<stdlib.h>
#define MAX 1000
#define size 50
int main ()
{
int count = 0;
char input[size];
char * preword[MAX];
while (scanf("%s",input)!= EOF){
preword[count] = input;
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
printf("the count is %d\n",count);
for (int i = 0; i < count; i++){
printf("preword[%d] is %s\n",i,preword[i]);
}
return 0;
}
I expect my input arrays from stdin will be stored in a two-dimensional char array. Below is the output in terminal after compilation. My input is a txt file, in which I have
hello world
I am a hero
It turns out that all strings stored in the two-d array are the last word.
preword[0] is hello
preword[1] is world
preword[2] is I
preword[3] is am
preword[4] is a
preword[5] is hero
the count is 6
preword[0] is hero
preword[1] is hero
preword[2] is hero
preword[3] is hero
preword[4] is hero
preword[5] is hero
Firstly here
char * preword[MAX];
preword is array of character pointer i.e each element is a char pointer & when you are doing like
preword[count] = input;
as #paddy pointed its copies input in every element of preword and it's the same pointer since you haven't allocated memory for preword[count], correct way is to allocate memory for each pointer and then copy.
Also use fgets() instead of scanf() here. For e.g
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 1000
#define size 50
int main (void)
{
int count = 0;
char input[size] = {0};
char * preword[MAX] = {0};
size_t retStrCspn = 0;
while (fgets(input, size, stdin) != NULL){
/* remove trailing new line if its stored at end of buffer by fgets() */
input[retStrCspn = strcspn(input, "\n")] = 0; /* remove the trailing & use the return value for allocating memory purpose \n */
preword[count] = malloc(retStrCspn + 1); /* Allocate memory for each pointer elements */
if(preword[count] != NULL) {
memcpy (preword[count], input, retStrCspn + 1); /* copy input buffer into each different memory location */
printf("preword[%d] is %s\n",count,preword[count]);
count++;
}
else {
/* #TODO malloc erro handling */
}
}
printf("the count is %d\n",count);
for (int i = 0; i < count && preword[i] != NULL; i++){
printf("preword[%d] is %s\n",i,preword[i]);
free(preword[count]); /* free dynamically allocated memory here*/
}
return 0;
}

Why following code snippets assignment gives confusing output?

I'm studying C. I came across with string arrays. I'm bit confused about the following codes. I was anticipating one kind of output; however, getting completely different kind of output or program crush due to read access violation.
I've run this code on visual studio 2017, with _CRT_SECURE_NO_WARNINGS
// case 1
char* name[2];
//name[0] = (char*)malloc(sizeof(char*) * 10);
//name[1] = (char*)malloc(sizeof(char*) * 10);
name[0] = "john";
name[1] = 'doe';
printf("%s\n", name[0]); // prints john
//printf("%s\n", name[1]); // gives read access violation exception, why??? even with dynamically allocated memory
// case 2
char* name2[2] = { "emma", "olsson" };
printf("%s\n", name2[0]); // prints emma
printf("%s\n", name2[1]); // prints olsson, why no error???
// case 3
for (int i = 0; i < 2; i++)
{
name[i] = name2[i];
}
printf("%s\n", name[0]); // prints emma
printf("%s\n", name[1]); // prints olsson, why no error???
// case 4
char inputName[10];
int i = 0;
while (i < 2)
{
fgets(inputName, sizeof(inputName), stdin); // first input: Max second input: Payne
char* pos = strchr(inputName, '\n');
if (pos != NULL)
*pos = '\0';
name[i++] = inputName;
}
printf("%s\n", name[0]); // prints Payne, why not Max???
printf("%s\n", name[1]); // prints Payne
For case 1, 'doe' is not a string.
Case 2 works because you are initializing you pointers with string literals.
Case 3 works too because you assign the same initialized pointer in case 2 to case 1 pointers. Your name array pointers are basically set to point to where name2 ones are pointing.
In case 4, you declared inputName which points to a set of 10 chars. Then each time you get a new input you are writing it to the same memory section. And by doing this:name[i++] = inputName;
you are not copying a new char array to name[i] as you might think. Instead, you are telling name[i] char pointer to point to inputName. So it is normal that name prints last input twice, because that's what inputName points to, as well as both name char pointers.
It is unclear whether OP's code runs within main() or a user-defined function and what kind of value returns. That said, after removing superfluous variable redeclarations, here's how I achieved working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char * name2[2]={ "emma", "olsson" };
char inputName[10];
char names[BUFSIZ];
int i = 0;
// case 1
name[0] = "john";
name[1] = "doe";
printf("%s %s\n", name[0],name[1]); //john doe
// case 2
printf("%s %s\n", name2[0],name2[1]);//emma olsson
// case 3
for (i = 0; i < 2; i++){
name[i] = name2[i];
}
printf("%s %s\n", name[0],name[1]);//emma olsson
// case 4
i=0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
strcat(names,inputName);
i++;
}
printf("\n%s\n",names);
return 0;
}
See live code here
OP should replace the single quotes around doe with double quotes which denote a null-terminated string. Single quotes are meant for a single character, i.e. 'a' refers to a byte value while "a" signifies a string containing two characters, an 'a' and a '\0'.
Also, OP should include two other libraries to facilitate execution. In particular, string.h is needed for the built-in string functions to execute properly.
Case 2 and Case 3 work because strings are encompassed by double quotes instead of single quotes. Note that in each case the "%s" format specifier for the printf() indicates that a string needs to be displayed.
In last case, fgets() with respect to stdin, upon success returns user input as a string. But that input will be overridden in the while loop, unless in each iteration you concatenate the old input with the new. Otherwise, when the inputName element values change because its address remains constant, only the latest input string displays. Here's some code that illustrates this point:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char inputName[10];
int i = 0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
printf("inputName: %p points to: %s",inputName,inputName);
name[i++] = inputName;
}
printf("\n name[0]: %p points to: %s\n name[1]: %p points to: %s",name[0],name[0],name[1],name[1]);
return 0;
}
Output:
inputName: 0x7fff8a511a50 points to: Maxine
inputName: 0x7fff8a511a50 points to: Pauline
name[0]: 0x7fff8a511a50 points to: Pauline
name[1]: 0x7fff8a511a50 points to: Pauline
See live code.
Incidentally, you don't need an array to display the names and indeed one may display the names outside of the loop as long as within the loop the code concatenates user input.

Stripping a sentence for only it's alpha characters

I'm trying to solve a code to strip a sentence down only to it's alpha character, using the following code, but the code always gives me a runtime error(The commented parts are steps I had taken to figure out the solution).
[Ex: Test'sen- tence should print Testsentence]
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFFER_LEN 1000
#define BUFFER_INCR 15
int main(void)
{
int buffer_length = BUFFER_LEN;
char *pString = malloc(BUFFER_LEN);/* initial array */
char *pTemp_start = pString;
long long int String_len = 0;
char *pTemp = NULL;
int copy = 0;
int count = 0;/*delete this after check*/
while((*pString++ = getchar()) != '\n')
{
String_len = pString - pTemp_start;
printf("\nThe character you inputted is: %c", *(pString+count++));
//getchar();
if(String_len == (buffer_length - 1))/*reserve one for newline*/
{
buffer_length += BUFFER_INCR;
pTemp = realloc(pString, buffer_length);/*reallocate space for
15 more chars.*/
pTemp_start = pTemp - String_len;
pString = pTemp;
free(pTemp);
pTemp = NULL;
if(!pString)
{
printf("The space couldn't be allocated");
return 1;
}
}
}
/*checks that can be done for addresses*/
//printf("\nThe length of the string is: %lld", pString - pTemp_start);
*(--pString) = '\0';
//printf("\nThe charcter at the end is: %d", *(pString + String_len - 1));
//printf("\nThe character at the mid is: %d", *(pString + 2));
printf("The input string is: %c", *pString);
/*code to remove spaces*/
for(int i = 0; i < (String_len + 1); i++)
{
if((isalnum(pString[i])))
{
*(pString + copy++) = *(pString +i);
}
}
*(pString + copy) = '\0';/*append the string's lost null character*/
printf("\nThe stripped string is: \n%s", pString);
return 0;
}
The code simply doesn't print anything that's inputted.
So you've got a conflict in your code between this line
while((*pString++ = getchar()) != '\n')
and lines like the following.
pTemp = realloc(pString, buffer_length);
The first line I've quoted is incrementing the position of pString within your allocated memory, but the second one is acting as if pString is still pointing to the start of it. realloc() won't work unless pString is pointing to the start of the allocated memory. You're then not checking the results of the realloc() call, assigning the new memory block to pString and then freeing the newly allocated memory. So you're definitely going to have unexpected results.
You also have to remember that stdin is buffered, so your code will wait until it's got an entire line to read before doing anything. And stdout is also buffered, so only lines that end in a \n will be output. So you probably want to have the following...
printf("The character you inputted is: %c\n", *pString);
...or something similar bearing in mind the issues with how you're using pString.
realloc(pString,...) does not add an allocated block, it replaces the one being reallocated (in this case, pString). So pString isn't (necessarily) a valid pointer after that call. Worse, you then free(pTemp), so you no longer have anything allocated.

How to input strings into an array in C?

I tried to get the inputs(strings) from user and store them in an array.But after I ran this code, the program instantly crashed.
#include <stdio.h>
int main() {
int i;
char *word[3];
for(i=0;i<3;i++)
{
printf(" Enter a word: ");
scanf("%s", &word[i]);
}
printf("%s ", word[0]);
return 0;
}
In this line:
scanf("%s", &word[i]);
You need to make sure word[i] is pointing somewhere, and has enough space to occupy the string entered. Since word[i] is a char * pointer, you need to at some time allocate memory for this. Otherwise, it is just a dangling pointer not pointing anywhere.
If you want to stick with scanf(), then you can allocate some space beforehand with malloc.
malloc() allocates requested memory on the heap, then returns a void* pointer at the end.
You can apply malloc() in your code like this:
size_t malloc_size = 100;
for (i = 0; i < 3; i++) {
word[i] = malloc(malloc_size * sizeof(char)); /* allocates 100 bytes */
printf("Enter word: ");
scanf("%99s", word[i]); /* Use %99s to avoid overflow */
/* No need to include & address, since word[i] is already a char* pointer */
}
Note: Must check return value of malloc(), because it can return NULL when unsuccessful.
Additionally, whenever you allocate memory with the use of malloc(), you must use free to deallocate requested memory at the end:
free(word[i]);
word[i] = NULL; /* safe to make sure pointer is no longer pointing anywhere */
Another approach without scanf
A more proper way to read strings should be with fgets.
char *fgets(char *str, int n, FILE *stream) reads a line from an input stream, and copies the bytes over to char *str, which must be given a size of n bytes as a threshold of space it can occupy.
Things to note about fgets:
Appends \n character at the end of buffer. Can be removed easily.
On error, returns NULL. If no characters are read, still returns NULL at the end.
Buffer must be statically declared with a given size n.
Reads specified stream. Either from stdin or FILE *.
Here is an example of how it can be used to read a line of input from stdin:
char buffer[100]; /* statically declared buffer */
printf("Enter a string: ");
fgets(buffer, 100, stdin); /* read line of input into buffer. Needs error checking */
Example code with comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUMSTR 3
#define BUFFSIZE 100
int main(void) {
char *words[NUMSTR];
char buffer[BUFFSIZE];
size_t i, count = 0, slen; /* can replace size_t with int if you prefer */
/* loops only for three input strings */
for (i = 0; i < NUMSTR; i++) {
/* read input of one string, with error checking */
printf("Enter a word: ");
if (fgets(buffer, BUFFSIZE, stdin) == NULL) {
fprintf(stderr, "Error reading string into buffer.\n");
exit(EXIT_FAILURE);
}
/* removing newline from buffer, along with checking for overflow from buffer */
slen = strlen(buffer);
if (slen > 0) {
if (buffer[slen-1] == '\n') {
buffer[slen-1] = '\0';
} else {
printf("Exceeded buffer length of %d.\n", BUFFSIZE);
exit(EXIT_FAILURE);
}
}
/* checking if nothing was entered */
if (!*buffer) {
printf("No string entered.\n");
exit(EXIT_FAILURE);
}
/* allocate space for `words[i]` and null terminator */
words[count] = malloc(strlen(buffer)+1);
/* checking return of malloc, very good to do this */
if (!words[count]) {
printf("Cannot allocate memory for string.\n");
exit(EXIT_FAILURE);
}
/* if everything is fine, copy over into your array of pointers */
strcpy(words[count], buffer);
/* increment count, ready for next space in array */
count++;
}
/* reading input is finished, now time to print and free the strings */
printf("\nYour strings:\n");
for (i = 0; i < count; i++) {
printf("words[%zu] = %s\n", i, words[i]);
free(words[i]);
words[i] = NULL;
}
return 0;
}
Example input:
Enter a word: Hello
Enter a word: World
Enter a word: Woohoo
Output:
Your strings:
words[0] = Hello
words[1] = World
words[2] = Woohoo
There seems to be a bit of confusion in this area. Your primary problem is you are attempting to write each word to the address of each of pointers you declare with char *word[3];. (not to mention you have no storage allocated at the location pointed to by each pointer -- but you never get there as you attempt to write to the address of each pointer with &word[i] rather than to the pointer itself)
While you can use scanf you will quickly run into one of the many pitfalls with taking user input with scanf that plague all new C programmers (e.g. failing to handle the '\n' left in the input buffer, failing to handle whitespace in strings, failing to limit the number of characters read/written, failing to validate the read or handle EOF, etc...)
A better approach is to simply use fgets and then trim the '\n' that fgets read and includes in the buffer to which it stores the string. A simple example would be:
#include <stdio.h>
#include <string.h>
#define NWDS 3 /* declare a constant for the maximum number of words */
int main (void) {
int i, n = 0;
char word[NWDS][50] = { "" }; /* provide storage or allocate */
for (i = 0; i < NWDS; i++) { /* for a max of NWDS */
printf ("Enter word : "); /* prompt */
if (!fgets (word[i], sizeof word[i], stdin)) /* read/validate */
break; /* protect against EOF */
size_t len = strlen (word[i]); /* get length */
if (word[i][len-1] == '\n') /* check for trailing '\n' */
word[i][--len] = 0; /* overwrite with nulbyte */
}
n = i; /* store number of words read */
putchar ('\n'); /* make it pretty */
for (i = 0; i < n; i++) /* output each word read */
printf (" word[%d] : %s\n", i, word[i]);
#if (defined _WIN32 || defined _WIN64)
getchar(); /* keep terminal open until keypress if on windows */
#endif
return 0;
}
Go ahead and cancel input at any time by generating an EOF during input (ctrl + d on Linux or ctrl + z on windoze), you are covered.
Example Use/Output
$ ./bin/wordsread
Enter word : first word
Enter word : next word
Enter word : last word
word[0] : first word
word[1] : next word
word[2] : last word
Looks things over, consider the other answers, and let me know if you have further questions.
char *word[3]; // <-- this is an array of 3 dangling pointers, of type char*
// they still point nowhere, we later need to set them to some allocated location.
...
for(i=0;i<3;i++) {
word[i] = malloc(some_max_size * sizeof(char)); // <-- allocate space for your word
printf(" Enter a word: ");
scanf("%s", word[i]); // <-- not &word[i]; word[i] is already a char* pointer
}
You are declaring word as array of pointer (char *word[3];). You have to allocate memory to store data. Allocate memory with malloc or similar functions before assigning values.
Yes the code crashes because declaring an array of character
pointers is not enough, you need to set the pointers to point
to memory where the strings can be stored.
E.g.
const int maxLen = 32;
char* word[3] = {NULL,NULL,NULL};
word[i] = malloc(maxLen);
then read the string from keyboard, to ensure that the string is not too
long use fgets and maxLen:
printf("Enter a word:");
fgets(word[i],maxLen,stdin);
#include <stdio.h>
int main(){
int n;
int i=0;
scanf("%d",&n);
char arr[n];
while(n>i){
scanf("%s",&arr[i]);
i+=1;
}
while(n-i<n){
printf(" %c ",arr[n-i]);
i-=1;
}
}
The code char *word[3] made a 3-element array of pointers!
See, you have basically created a character array of pointers, so you cannot put a "string" into each one of them, because the type of a pointer variable is long hexadecimal.

Resources