I want to preface my question by mentioning that I am a CS student that is very new to coding.
I am attempting to write a script that will add a set of array of characters to two arrays that are nested within a loop. The array of characters are prefixes for two courses, and I am using a function called "matcher" (that accepts an array that will hold a prefix, and an integer that holds the course number that we want to match to the corresponding prefix) within the loop.
The issue that I am facing is that when I run this, the first array(.prefix3) gets concatenated with the prefix for the second array(.prefix4), which seems to happen after the loop runs for a second time. I am unsure as to why this is occurring, specially since each array can only hold 7 characters. Here is the code, thank you all in advance:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[20];
int ID;
int number_of_courses;
int course_numbers[4];
char prefix1[7];
char prefix2[7];
char prefix3[7];
char prefix4[7];
int taken;
} student_info;
void matcher(char *,int );
int main()
{
student_info students[100];
int j=2;
int course_placeholder;
for(int i=0;i<2;i++)
{
printf("Enter course number %d:",i+1);//Type "9696" or "1232"
scanf("%d",&course_placeholder);
if(j==1)
{
matcher(students[0].prefix2,course_placeholder);
}
else if(j==2)
{
matcher(students[0].prefix3,course_placeholder);//this is concatenating the string for some reason. Trying to determine why.
}
else if(j==3)
{
matcher(students[0].prefix4,course_placeholder);
}
j++;
}
printf("%s\n%s\n",students[0].prefix3,students[0].prefix4);//students[0].prefix3 is concatenating for an unknown reason.
return 0;
}
void matcher(char *prefix_placeholder,int course_placeholder)
{
if(course_placeholder==9696)
{
strcpy(prefix_placeholder,"MAT 236");
}
else if(course_placeholder==1232)
{
strcpy(prefix_placeholder,"COP 220");
}
}
Although you cannot see it, string literals with 7 visible characters, such as this one:
"COP 220"
^ - NULL terminator is implied here
actually contain 8 characters, not 7. The last character is \0 ( AKA NULL )
So, when allocating memory in an array which is designed to contains C strings ( defined as a NULL terminated char array ) always include space enough for the NULL
char prefix1[8] = {0}; //1 extra element for NULL, all elements initialized to NULL
To test this yourself, do this:
size_t size = sizeof "MAT 236" ;//expect size == 8 (includes NULL)
int len = strlen("MAT 236");//expect len == 7 (does not include NULL)
The arrays
char prefix1[7];
char prefix2[7];
char prefix3[7];
char prefix4[7];
are too short to store 7-character strings like "MAT 236" and "COP 220" because they require at least 8-character arrays including terminating null-characters.
Allocate enough elements to avoid troubles.
Related
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(;i<100;i++)
{
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(;i<100;i++)
{
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
You are returning a pointer to automatic variables en and de which are stored in the stack. This in turn means after returning from the functions encrypt and decrypt their place in the memory can be used by any other variable.
so to correct that, you need to define en and de as static.
const char *encrypt(char *str){
static char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
const char *decrypt(char *str1){
static char de[100];
int i=0;
for(;i<100;i++){
de[i]=str1[i]-3;
}
de[i]='\0';
return de;
}
Though a more suitable and safer way to implement that would be:
#include<stdio.h>
void encrypt(char *str, char *encStr);
void decrypt(char *str1, char* decStr);
int main()
{
char str[100], encDecStr[100];
//Encryption
printf("Enter String for encryption\n");
scanf("%s", str);
encrypt(str, encDecStr);
printf("%s after encryption is %s\n",str,encDecStr);
//Decryption
printf("Enter String for decryption\n");
scanf("%s", str);
decrypt(str, encDecStr);
printf("%s after decryption is %s",str,encDecStr);
return 0;
}
void encrypt(char *str, char *encStr)
{
for(char *c = str; *c != '\0'; c++)
{
*encStr++ = *c + 1;
}
*encStr='\0';
}
void decrypt(char *str1, char* decStr)
{
for(char *c = str1; *c != '\0'; c++)
{
*decStr++ = *c - 1;
}
*decStr++='\0';
}
Note: The code was not fully tested for different use cases.
There are quite a number of errors in your code:
Returning arrays with local storage duration:
The array's life time ends (i.e. it ceases to exist) as soon as you exit from the function, thus the pointer returned is dangling, reading from it is undefined behaviour
You write beyond the bounds of your local array: en[i] = '\0' with i being 100 after the loop is out of the range of valid indices from 0 to 99, which again is undefined behaviour.
You have differing offsets for encrypting (1) and decrypting (3).
Simply adding an offset without further checks (or modulo operations) will produce different character sets for input and output strings (might be your least problem...).
You always en-/decode the entire array, which is more than actually needed. Additionally the terminating null character then is encoded as well, resulting in different lengths of input and output and garbage at the end of encoded string.
Use of gets is dangerous as it allows a user to write beyond the input array, resulting in undefined behaviour. This is the reason why it actually has been removed from C language with C11 standard – which introduces a safe alternative gets_s. Yet another alternative (especially for pre-C11 code) is fgets.
For the dangling pointer problem there are several options:
Making the array static (as mentioned already):The disadvantage of this approach is that the function is not thread-safe any more. Additionally calling the function more than once overwrites previous results, if you haven't evaluated already or copied them they are lost.
Returning a dynamically allocated array, see malloc function. This comes with the risk of the caller forgetting to free the allocated memory again, which would result in a memory leak
Changing the input array in place: Disadvantage of is having to copy the input into a backup if it is yet needed afterwards.
Letting the caller provide the buffer.
Last option is most flexible and most idiomatic one, so I'll concentrate on this one:
void caesar(char const* input, char* output, int offset)
{
int const NumChars = 'z' - 'a';
offset = offset % NumChars + NumChars;
// ^ assures valid range, can still be negative
// ^ assures positive value, possibly
// out of range, but will be fixed later
for(;*input; ++input, ++output)
{
int c = *input - 'a';
// distance from character a
c = (c + offset) % NumChars;
// ^ fixes too large offset
*output = 'a' + c;
}
// as now iterating *until* null character found we now *need*
// to add it (in contrast to original version with whole array!)
*output = 0;
}
This variant includes an interesting idea: Let the caller define the offset to be applied! The modulo operation assures the valid range of the character, no matter how large the offset is. The great thing about: If a user encoded with some number n, exactly the same function can be used to decode again with -n (which is why I simply named it caesar according to the algorithm it implements). Note that this is untested code; if you find a bug please fix yourself...
Be aware, though, that this code still has two weaknesses:
It assumes ASCII encoding or compatible – at least one where letters a to z are in contiguous range, a is first character, z is last one. This is not true for all encodings, though, consider the (in-?)famous EBCDIC.
It assumes all input is in range of Latin minuscules only (from a - z), it does not consider white-space, digits, capital letters, punctuation marks... You might want to include special handling for all of these or at least the ones you might use.
You could fix these e.g. (many other variants are thinkable as well) by
converting all characters to either upper or lower case (toupper((unsigned char)*input) – assuming case doesn't matter)
search in an array of valid characters ("ABC...XYZ012...89") for the appropriate index and if found encode like above with NumChars being array length, otherwise (whitespace, punctuation) just leave as is.
In any case, the function would then be called like:
char input[128]; // prefer powers of 2 for array lengths...
char en[sizeof(input)];
char de[sizeof(input)];
gets_s(input, sizeof(input));
caesar(input, en, 7);
// en contains encrypted string, could e.g. be printed now
caesar(en, de, -7);
// de contains decrypted string
// you could even encode/decode in place:
caesar(input, input, 7);
// just be aware that this will fail, though, for the case if input
// and output overlap and input starts before output, as then at
// some point already encoded values will be read as input again:
// caesar(input, input + 1, 7) fails!!!
There's some issues in your code :
Not a very big issue for a beginner , but you should avoid gets function.
Because it doesn't check the input , it can cause buffers overflow and various security problems , try using fgets instead.
In encrypt , and decrypt functions , you are returning the address of an array located in the stack of the function , look :
const char *encrypt(char *str){
char en[100];
int i=0;
for(;i<100;i++){
en[i]=str[i]+1;
}
en[i]='\0';
return en;
}
Here , Since the en array is declared inside the function , after the return you may get garbage string when trying to read it.
The solution here , is to either malloc it , or declare a static array outside the function , and initialize it.
You are encrypting by adding 1 to the value of the string , and decrypt it by retrieving 3 . I don't know if this is what you intended to do.
Here's a new version of your code , try to check if it suits your need :
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
static char de[100] , en[100] ;
const char *decrypt(char *str1){
memset(de , 0 , 100) ;
int i=0;
for(;i<strlen(str1);i++){
de[i]=str1[i]-1;
}
de[i]='\0';
return (const char*) de;
}
const char* encrypt(char* str){
memset(en , 0 , 100) ;
int i=0;
for(;i<strlen(str);i++){
en[i]=str[i]+1;
}
en[i]='\0';
return (const char*) en;
}
int main(){
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str);
encrypt(str);
printf("%s after encryption is %s\n",str,encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1);
decrypt(str1);
printf("%s after decryption is %s",str1,decrypt(str1));
return 0;
}
Your code does not handle a special case for the character 'z'. Thus
en[i]=str[i]+1;
Causes the character '{' to be written to the array en instead. For learning more about why this happens, I recommend you look at ASCII tables and looking at the integer values for alphabets.
Secondly, did you mean to type -3 in there?
de[i]=str1[i]-3;
This won't work if you're planning on using the decrypt() function to decrypt strings that you made using encrypt() because you're adding 1 to the character while encrypting and then subtracting a different number when decrypting, so the result will appear garbled.
I rewrote your code for you, since this is a beginner program, I made as little changes as possible so you can understand it. I WOULD HIGHLY RECOMMEND NOT USING gets() though... See here.
#include<stdio.h>
const char *encrypt(char *str);
const char *decrypt(char *str1);
int main()
{
char str[100],str1[100];
//Encryption
printf("Enter String for encryption\n");
gets(str); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
encrypt(str);
printf("%s after encryption is %s\n", str, encrypt(str));
//Encryption
printf("Enter String for decryption\n");
gets(str1); // DON'T USE GETS!!! USE fgets(str, 100, stdin);
decrypt(str1);
printf("%s after decryption is %s", str1, decrypt(str1));
return 0;
}
const char *encrypt(char *str)
{
char en[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'z')
{
en[i] = 'a';
continue;
}
en[i] = str[i] + 1;
}
en[i] = '\0';
return en;
}
const char *decrypt(char *str1)
{
char de[100];
int i=0;
for(; i<100; i++)
{
if (str[i] == 'a')
{
en[i] = 'z';
continue;
}
de[i] = str1[i] - 1;
}
de[i] = '\0';
return de;
}
Some criticisms
Like I said, gets() is really bad... See here for more details. Although it might be too complicated for you... A better alternative is fgets!
fgets(str, num, stdin)
takes user input from the console, and then stores it inside the array str, which must be large enough to store at least num characters. Don't worry about stdin if you don't know what that means. But be sure to always write it when using fgets as an alternative to gets
Like others have already posted, albeit using more technical jargon, it's a bad idea to declare an array inside a function and then return that array. You know the function ends when the return statement is hit, and at that point all the variables that were declared inside the function will get destroyed.
That doesn't necessarily mean that you can't read the data that was in them, but it becomes a probabilistic game where there's a teeny-tiny chance that the array will get corrupted after the function exits and before the data in that array is read. This is technically Undefined Behaviour.
I hope you know about pointers. You can modify the array which you passed as a parameter directly and then return that array, thus avoiding accessing an array outside it's lifetime.
Ok so i am trying to write a function that checks whether or not a letter of a word exists within an array of strings(It does that for every letter in the word). After tinkering with it for a while, i figured that it crashed when it tried to use the strcmp(). I don't know what i am doing wrong since i just started learning C so any help would be appreciated. Here is the function:
char SingleChar(char *lex, int wordnum,char *word){
int i,j,k;
for(i=0;i<strlen(word);i++){
for(j=0;j<wordnum;j++){
for(k=0;k<strlen(lex[j]);k++){
if(strcmp(word[i],lex[k])){
return word[i];
}
}
}
}
return 0;
}
You have a misunderstanding about what char * means. It is a pointer to character. In C string are just a pointer to a character, flowed by other characters and a null terminator. What this means in your case, is that lex is a single string, not a list of strings.
ie
char *a = "imastring"; denotes that a is the address of a sequential piece of memory containing the characters [i][m][a][s][t][r][i][n][g][\0]. In C the null terminator is used to denote the end of a string.
What this means is that when you are calling strlen(lex[j]) you are just referencing a single character in lex and then reading to the end of the string, so your result will just decrease monotonically.
You probably want to do is use a double pointer. char ** list will point to an address, which points to an address referencing a block of sequential characters.
char ** list = (char **)malloc(sizeof(char *) * 5); would allocate you 5 sequential memory address which could then point to strings themselves. And you can assign them values as follows.
list[0] = a
I hope this helps.
Don't really see an array of strings... Your C file should look roughly like this:
#include <stdio.h>
char SingleChar(char *lex, int wordnum, char *word){"your function in here"};
int main(){
// Declare your variables here
// Call your function here SingleChar(params)
return 0;
}
To compare characters:
if(word[i]==lex[k]){
return word[i];
break;
}
Not quite sure what you are trying to do with your function other than that. You need to be more specific, I don't see your array of strings input.
In C there is no true string type. A string in C is just an array of characters.
An array of strings would be an array of pointers to an array of characters in memory.
If you wanted to check for a letter within an array of "strings".
You would want a pointer that moves through each letter of the array and compares each character.
The strcmp() function will return true (1) or false (0), depending on whether the strings are equal or not.
So what you'd want I think is for your program to compare the characters of your word with every other word in the array of strings.
This program goes through the entire word then tells you if the letter exists.
For each letter of whatever word you enter.
--
#include <stdio.h>
#include <string.h>
/*
Function to check for a letter of a word
in an array of strings */
void singleChar(char *word,int arrlength, char *strings[])
{
int length = 0;
length = strlen(word); /* Calculates the length of the string */
for(int y = 0; y < arrlength ; y++) /*Increments to the next word in the array */
{
for(int i=0; i <= length ; i++) /*increments to the next letter of the word you want to check */
{
for(int x=0; x < strlen(strings[y]) ; x++) /*Increments x based on the length of the string */
{
char *p = strings[y];
if(word[i] == p[x]) /*Compares the the first letter of both strings */
{
printf("The letter %c exists.\n", word[i]);
}
}
}
}
}
int main ( void )
{
/*Example */
char *p = "Hello";
char *a[2];
a[0]="Hello";
singleChar(p, 1,a);
}
I'm new in C programming and I'm trying to make a function that sends what is stored in one array character that each time is going to change. So if my array is first "hello" it should send only 5 characters, but if later is "goodbye" it should send 7. What I want to avoid is have to write a lot of characters if I want to extend my array, like in this:
int say (buttonpressed){
char a[11] = {'h','e','l','l','o'};
int i;
for (i = 0;i<12;i++)
{
U2TXREG = a[i];
while(U2STAbits.TRMT==0);
}
buttonpressed = 0;
return 0;
}
I would apreciate any ideas, thanks!
You need to know the length of your array or use an End-Of-String character (which usually is \x0 - a binary zero).
int say (buttonpressed){
char* a = "hello";
int i;
int size=strlen(a);
for (i = 0;i<size;i++)
{ //rest as before
By using a string constant you initialize the array to end with a null (0) char. This can then be used to find the string length using strlen.
I have also just used a pointer to the string constant as you are not modifying it.
You really need to explain more what do you want to do.
From what you say I understand that you want to change the size and contents of your array without changing the for loop.
If that's the case you can use this:
#define ARRAY_LENGTH 12 /* 12 is an example */
int say (buttonpressed)
{
char a[ARRAY_LENGTH] = { . . . . };
int i;
for(i =0; i<ARRAY_LENGTH; i++){
...
}
....
}
I would store the data and the actual size in a struct (similiar to how you would use a std::vector in C++
struct vec{
char data[11];
unsigned int size;
}
Then in your for loop can just loop from i=0 to i
If your array is always going to be a string, a c-style string would be idiomatic in c. This is just an char array terminated by \0, and test for \0 while looping over the array.
Good day all,
I have two array which I want to copy some data from the first array to the second array without repeating any values in the second array.Could someone tell me what I am not getting here.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
main()
{
char *hours;
char *strl;
hours = {0,0,0,0,1,1,2,2,2,5,5,10,10,10,10,10,.,.,.,23};
strl=calloc(100,sizeof(char));
sprintf(strl, "%d", hours);
if(strcmp(strl, hours))
{
if(*strl)
strcpy(strl,hours);
}
printf("%s ",strl;
}
You probably want to do something more like:
char *dst = strl;
char *cur = hours;
char prev = '\0';
while(*cur) {
if(*cur != last) {
prev = *dst = *cur;
dst++;
}
cur++;
}
Oh yea and as noted by others, your arrays aren't terminated with '\0', so standard string functions don't work (And for that matter neither will my loop).
Second none of the standard C library functions do what you want... I'll leave it up to you to fix my loop. (Note it only works if the array is sorted)
As James said, you can't use string functions because your arrays aren't NUL-terminated. Even if you could, strcmp would always return non-zero (specifically negative), and *strl would always be 0, which means the inner if always fails. Finally strcpy does not eliminate any duplicates. If your array is sorted, you can do this by checking for duplicate consecutive values. Otherwise, you can use a hash set/hash table like GHashTable.
First of all, you have two arrays of chars. Now, in C, arrays of chars are often used to store strings, but you are not doing that. These are not strings at all, so forget all about the string functions in the library.
What you actually have are two arrays of tiny integers, so you handle them as you would an int array.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *hours;
char *strl;
int i;
int j;
char last;
/* I'm going to assume the the values in hours are sorted. */
hours={0,0,0,0,1,1,2,2,2,5,5,10,10,10,10,10,.,.,.,23}
strl=calloc(100,sizeof(char));
j = 0;
last = hours[0];
for(i=1; i < 100; ++i) // I'm going to assume hours has 100 items
{
if (hours[i] != last)
{
strl[j++] = last;
last = hours[i];
}
}
strl[j++] = last; // UPDATE (Thanks, Matthew)
}
/* printf("%s ",strl;
You'll need a different way of printing you results */
}
An array of pointers to strings is provided as the input. The task is to reverse each string stored in the input array of pointers. I've made a function called reverseString() which reverses the string passed to it. This functions works correctly as far as i know.
The strings stored/referenced in the input array of pointers are sent one by one to the reverseString() function. But the code hangs at some point in the reverseString() function when the values of the passed string are swapped using a temp variable. I can't figure out why the code is hanging while swapping values. Please help me with this.
The code is as follows:
#include <stdio.h>
void reverseString(char*);
int main()
{ char *s[] = {"abcde", "12345", "65gb"};
int i=0;
for(i=0; i< (sizeof(s)/sizeof(s[0]) ); i++ )
{ reverseString(s[i]);
printf("\n%s\n", s[i]);
}
getch();
return 0;
}//end main
void reverseString(char *x)
{ int len = strlen(x)-1;
int i=0;
char temp;
while(i <= len-i)
{ temp = x[i];
x[i] = x[len-i];
x[len-i] = temp;
i++;
}
}//end reverseString
You are trying to change string literals.
String literals are usually not modifiable, and really should be declared as const.
const char *s[] = {"abcde", "12345", "65gb"};
/* pointers to string literals */
If you want to make an array of modifiable strings, try this:
char s[][24] = {"abcde", "12345", "65gb"};
/* non-readonly array initialized from string literals */
The compiler will automatically determine you need 3 strings, but it can't determine how long each needs to be. I've made them 24 bytes long.
The strings ("abcde" etc) could be stored in readonly memory. Anything is possible when you try to modify those strings, therefore. The pointers to the strings are modifiable; it is just the strings themselves that are not.
You should include <string.h> to obtain the declaration of strlen(3), and another header to obtain the function getch() - it is not in <stdio.h> on my MacOS X system (so I deleted the call; it is probably declared in either <stdio.h> or <conio.h> on Windows).
Hope this helps you! what i am doing here is that i am going to the address of the last character in the string then printing them all by decreasing the pointer by 1 unit (for character its 2 bytes(please check)).
//program to reverse the strings in an array of pointers
#include<stdio.h>
#include<string.h>
int main()
{
char *str[] = {
"to err is human....",
"But to really mess things up...",
"One needs to know C!!"
};
int i=0; //for different strings
char *p; //declaring a pointer whose value i will be setting to the last character in
//the respective string
while(i<3)
{
p=str[i]+strlen(str[i])-1;
while(*p!='\0')
{
printf("%c",*p);
p--;
}
printf("\n");
i++;
}
}